lwip 1.4 - DM9161A PHY

After reading topic http://mbed.org/forum/mbed/topic/3684/?page=1#comment-18473, i created the lpc_phy_DM9161A.c file (used lpc_phy_lan8720.c as a template).

Partially working

Auto negotiation and DHCP are OK - ethernet communication is not working.

There seems to be a communication problem between the EMAC and PHY (timing?). Any ideas on how to resolve this issue are welcome.

A debug log is available at /media/uploads/frankvnk/tcpsocket_helloworld_with_dm9161a_phy_-_debug_log.txt. The log file indicates a pbuf problem. Further investigation led me to following webpage: http://www.lpcware.com/content/forum/lwip-sample-fail#comment-1785. I tried again with the mentioned modification but then DHCP does not work. I don't know if this modification also needs to be implemented (not present in the current lwip library).

How to test

import http://mbed.org/users/mbed_official/code/TCPSocket_HelloWorld/ into the mbed compiler.

Goto folder EthernetInterface\lwip-eth\arch#

Delete lpc_phy_dp83848.c.

Copy lpc_phy_DM9161A.c into this folder.

Add following MAC address definition in main.cpp (before 'EthernetInterface eth;').

       extern "C" void mbed_mac_address(char * mac)
       {
       // define your own MAC Address
         mac[0] = 0x00;  
         mac[1] = 0x1F;  
         mac[2] = 0x33;  
         mac[3] = 0x42;  
         mac[4] = 0xFC;  
         mac[5] = 0x6F;           
       };

When used with the Mini-DK hardware

Modify EthernetInterface\lwip-eth\arch\lpc_emac_config.h:

Change #define LPC_PHYDEF_PHYADDR 1 to #define LPC_PHYDEF_PHYADDR 19

On the Mini-DK, sometimes no IP address is obtained when the 'Reset' button is pressed after programming the device. Disconnect and reconnect the device and press the 'Reset' button again to restart.

Revision:
0:6901daab33f0
Child:
2:e8cdfd3c70f5
diff -r 000000000000 -r 6901daab33f0 lpc_phy_DM9161A.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lpc_phy_DM9161A.c	Tue Jan 29 12:45:31 2013 +0000
@@ -0,0 +1,420 @@
+/**********************************************************************
+* $Id$        lpc_phy_DM9161A.c            2013-01-28
+*//**
+* @file        lpc_phy_DM9161A.c
+* @brief       DM9161A PHY status and control.
+* @version     1.0
+* @date        14 Jan. 2013
+* @author      Frank Vannieuwkerke
+*              based on NXP MCU SW Application Team lpc_phy_dp83848.c
+*              Copyright(C) 2011, NXP Semiconductor
+*              All rights reserved.
+*
+*
+*
+* @NOTES:
+*  1. How to test : import http://mbed.org/users/mbed_official/code/TCPSocket_HelloWorld/ into the mbed compiler.
+*
+*  2. Open EthernetInterface\lwip-eth\arch folder
+*     Delete 'lpc_phy_dp83848.c'.
+*     Copy 'lpc_phy_DM9161A.c' (this file) into this folder.
+*
+*  3. When used with the Mini-DK hardware:
+*     Modify EthernetInterface\lwip-eth\arch\lpc_emac_config.h:
+*       Change #define LPC_PHYDEF_PHYADDR 1  to  #define LPC_PHYDEF_PHYADDR 19
+*
+*     Add following MAC address definition in main.cpp (before 'EthernetInterface eth;').
+*       extern "C" void mbed_mac_address(char * mac)
+*       {
+*       // define your own MAC Address
+*         mac[0] = 0x00;  
+*         mac[1] = 0x1F;  
+*         mac[2] = 0x33;  
+*         mac[3] = 0x42;  
+*         mac[4] = 0xFC;  
+*         mac[5] = 0x6F;           
+*       };
+*
+*
+*
+*
+***********************************************************************
+* Software that is described herein is for illustrative purposes only
+* which provides customers with programming information regarding the
+* products. This software is supplied "AS IS" without any warranties.
+* NXP Semiconductors assumes no responsibility or liability for the
+* use of the software, conveys no license or title under any patent,
+* copyright, or mask work right to the product. NXP Semiconductors
+* reserves the right to make changes in the software without
+* notification. NXP Semiconductors also make no representation or
+* warranty that such application will be suitable for the specified
+* use without further testing or modification.
+**********************************************************************/
+
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/tcpip.h"
+#include "lwip/snmp.h"
+#include "lpc_emac_config.h"
+#include "lpc_phy.h"
+
+/** @defgroup DM9161A_phy    PHY status and control for the DM9161A.
+ * @ingroup lwip_phy
+ *
+ * Various functions for controlling and monitoring the status of the
+ * DM9161A PHY. In polled (standalone) systems, the PHY state must be
+ * monitored as part of the application. In a threaded (RTOS) system,
+ * the PHY state is monitored by the PHY handler thread. The MAC
+ * driver will not transmit unless the PHY link is active.
+ * @{
+ */
+
+/** \brief DM9161A PHY register offsets */
+#define DM9161A_BMCR_REG         0x00        /**< Basic Mode Control Register */
+#define DM9161A_BMSR_REG         0x01        /**< Basic Mode Status Reg */
+#define DM9161A_IDR1_REG         0x02        /**< PHY ID 1 Reg  */
+#define DM9161A_IDR2_REG         0x03        /**< PHY ID 2 Reg  */
+#define DM9161A_ANAR_REG         0x04        /**< Auto_Neg Advt Reg  */
+#define DM9161A_ANLPAR_REG       0x05        /**< Auto_neg Link Partner Ability Reg */
+#define DM9161A_ANER_REG         0x06        /**< Auto-neg Expansion Reg  */
+#define DM9161A_DSCR_REG         0x10        /**< Specified Configuration Reg */
+#define DM9161A_DSCSR_REG        0x11        /**< Specified Configuration and Status Reg */
+#define DM9161A_10BTCSR_REG      0x12        /**< 10BASE-T Configuration and Satus Reg */
+#define DM9161A_MDINTR_REG       0x15        /**< Specified Interrupt Reg */
+#define DM9161A_RECR_REG         0x16        /**< Specified Receive Error Counter Reg */
+#define DM9161A_DISCR_REG        0x17        /**< Specified Disconnect Counter Reg  */
+#define DM9161A_RLSR_REG         0x18        /**< Hardware Reset Latch State Reg  */
+
+/** \brief DM9161A BMCR register definitions */
+#define DM9161A_RESET            (1 << 15)   /**< 1= S/W Reset */
+#define DM9161A_LOOPBACK         (1 << 14)   /**< 1=loopback Enabled */
+#define DM9161A_SPEED_SELECT     (1 << 13)   /**< 1=Select 100MBps */
+#define DM9161A_AUTONEG          (1 << 12)   /**< 1=Enable auto-negotiation */ 
+#define DM9161A_POWER_DOWN       (1 << 11)   /**< 1=Power down PHY */
+#define DM9161A_ISOLATE          (1 << 10)   /**< 1=Isolate PHY */
+#define DM9161A_RESTART_AUTONEG  (1 << 9 )   /**< 1=Restart auto-negoatiation */
+#define DM9161A_DUPLEX_MODE      (1 << 8 )   /**< 1=Full duplex mode */
+#define DM9161A_COLLISION_TEST   (1 << 7 )   /**< 1=Perform collsion test */
+
+/** \brief DM9161A BMSR register definitions */
+#define DM9161A_100BASE_T4       (1 << 15)   /**< T4 mode */
+#define DM9161A_100BASE_TX_FD    (1 << 14)   /**< 100MBps full duplex */
+#define DM9161A_100BASE_TX_HD    (1 << 13)   /**< 100MBps half duplex */
+#define DM9161A_10BASE_T_FD      (1 << 12)   /**< 10MBps full duplex */
+#define DM9161A_10BASE_T_HD      (1 << 11)   /**< 10MBps half duplex */
+#define DM9161A_MF_PREAMB_SUPPR  (1 << 6 )   /**< Preamble suppress */
+#define DM9161A_AUTONEG_COMP     (1 << 5 )   /**< Auto-negotation complete */
+#define DM9161A_RMT_FAULT        (1 << 4 )   /**< Fault */
+#define DM9161A_AUTONEG_ABILITY  (1 << 3 )   /**< Auto-negotation supported */
+#define DM9161A_LINK_STATUS      (1 << 2 )   /**< 1=Link active */
+#define DM9161A_JABBER_DETECT    (1 << 1 )   /**< Jabber detect */
+#define DM9161A_EXTEND_CAPAB     (1 << 0 )   /**< Supports extended capabilities */
+
+/** \brief DM9161A ANAR and ANLPAR register definitions */
+#define DM9161A_NP               (1 << 15)   /**< No next page - always = 0 */
+#define DM9161A_ACK              (1 << 14)   /**< 1 = Link partner ability data reception acknowledged */
+#define DM9161A_RF               (1 << 13)   /**< 1 = Local device senses a fault condition */
+#define DM9161A_FCS              (1 << 10)   /**< 1 = Controller chip supports flow control ability */
+#define DM9161A_T4               (1 << 9 )   /**< No 100BASE-T4 is supported  - always = 0 */
+#define DM9161A_TX_FDX           (1 << 8 )   /**< 1 = 100BASE-TX full duplex is supported by the local device */
+#define DM9161A_TX_HDX           (1 << 7 )   /**< 1 = 100BASE-TX half duplex is supported by the local device */
+#define DM9161A_10_FDX           (1 << 6 )   /**< 1 = 10BASE-T full duplex is supported by the local device */
+#define DM9161A_10_HDX           (1 << 5 )   /**< 1 = 10BASE-T half duplex is supported by the local device */
+#define DM9161A_AN_IEEE_802_3    0x0001      /**< this device supports IEEE 802.3 CSMA/CD */
+
+/** \brief DM9161A ANER register definitions */
+#define DM9161A_PDF              (1 << 4 )   /**< 1 = A fault detected via parallel detection function */
+#define DM9161A_LP_NP_ABLE       (1 << 3 )   /**< 1 = Link partner, next page available */
+#define DM9161A_NP_ABLE          (1 << 2 )   /**< No next page - always = 0 */
+#define DM9161A_PAGE_RX          (1 << 1 )   /**< New page received - cleared when reg 6 is read */
+#define DM9161A_LP_AN_ABLE       (1 << 0 )   /**< 1 = Link partner supports auto-negotiation */
+
+/** \brief DM9161A DSCR register definitions */
+#define DM9161A_BP4B5B           (1 << 15)   /**< 1 = 4B5B encoder and 5B4B decoder function bypassed */
+#define DM9161A_BP_SCR           (1 << 14)   /**< 1 = Scrambler and descrambler function bypassed */
+#define DM9161A_BP_ALIGN         (1 << 13)   /**< 1 = Receive and Transmit functions disabled */
+#define DM9161A_BP_ADPOK         (1 << 12)   /**< 1 = Force signal detector (SD) active - ONLY FOR DEBUG */
+#define DM9161A_REPEATER         (1 << 11)   /**< 1 = Repeater mode - latched at power up reset */
+#define DM9161A_TX               (1 << 10)   /**< 1 = 100BASE-TX operation */
+#define DM9161A_RMII_ENABLE      (1 << 8 )   /**< 1 = Enable Reduced MII */
+#define DM9161A_F_LINK_100       (1 << 7 )   /**< 1 = Force 100Mbps good link status */
+#define DM9161A_SPLED_CTL        (1 << 6 )   /**< 1 = Disable SPEEDLED output and enable SD signal monitor - ONLY FOR DEBUG  */
+#define DM9161A_COLLED_CTL       (1 << 5 )   /**< 1 = FDX/COLLED output is configured to indicate Fullduplex Collision status */
+#define DM9161A_RPDCTR_EN        (1 << 4 )   /**< 1 = Enable automatic reduced power down */
+#define DM9161A_SM_RST           (1 << 3 )   /**< 1 = Reset state machine - auto cleared after reset */
+#define DM9161A_MFP_SC           (1 << 2 )   /**< 1 = MF preamble suppression bit on */
+#define DM9161A_SLEEP            (1 << 1 )   /**< 1 = sleep mode */
+#define DM9161A_RLOUT            (1 << 0 )   /**< 1 = 1, loop out the received data to the transmit channel */
+
+/** \brief DM9161A DSCSR register definitions */
+#define DM9161A_SPEEDMASK        (15 << 12)  /**< Speed and duplex mask */
+#define DM9161A_100FDX           (1 << 15)   /**< 1 = 100MB full duplex */
+#define DM9161A_100HDX           (1 << 14)   /**< 1 = 100MB half duplex */
+#define DM9161A_10FDX            (1 << 13)   /**< 1 = 10MB full duplex */
+#define DM9161A_10HDX            (1 << 12)   /**< 1 = 10MB half duplex */
+
+/** \brief DM9161A 10BTCSR register definitions */
+#define DM9161A_LP_EN            (1 << 14)   /**< 1 = Transmission of link pulses enabled */
+#define DM9161A_HBE              (1 << 13)   /**< 1 = Heartbeat function enabled */
+#define DM9161A_SQUELCH          (1 << 12)   /**< 1 = normal squelch */
+#define DM9161A_JABEN            (1 << 11)   /**< 1 = Jabber function enabled */
+#define DM9161A_10BT_SER         (1 << 10)   /**< 1 = 10BASE-T GPSI mode selected */
+#define DM9161A_POLR             (1 << 0 )   /**< 1 = 10Mbps cable polarity is reversed */
+
+/** \brief DM9161A MDINTR register definitions */
+#define DM9161A_INTR_PEND        (1 << 15)   /**< Interrupt pending */
+#define DM9161A_FDX_MASK         (1 << 11)   /**< Full-duplex interrupt mask */
+#define DM9161A_SPD_MASK         (1 << 10)   /**< Speed interrupt mask */
+#define DM9161A_LINK_MASK        (1 << 9 )   /**< Link interrupt mask */
+#define DM9161A_INTR_MASK        (1 << 8 )   /**< Master interrupt mask */
+#define DM9161A_FDX_CHANGE       (1 << 4 )   /**< 1 = indicates a change of duplex since last register read */
+#define DM9161A_SPD_CHANGE       (1 << 3 )   /**< 1 = indicates a change of speed since last register read */
+#define DM9161A_LINK_CHANGE      (1 << 2 )   /**< 1 = indicates a change of link since last register read */
+#define DM9161A_INTR_STATUS      (1 << 0 )   /**< 1 = indicates that the interrupt mask is off */
+
+/** \brief DM9161A RLSR register definitions */
+#define DM9161A_LH_LEDMODE       (1 << 15)   /**< LEDMODE pin reset latch value */
+#define DM9161A_LH_MDINTR        (1 << 14)   /**< MDINTR pin reset latch value */
+#define DM9161A_LH_CSTS          (1 << 13)   /**< CABLESTS pin reset latch value */
+#define DM9161A_LH_ISO           (1 << 12)   /**< TXCLK pin reset latch value */
+#define DM9161A_LH_RMII          (1 << 11)   /**< COL pin reset latch value */
+#define DM9161A_LH_TP10SER       (1 << 10)   /**< RXCLK pin reset latch value */
+#define DM9161A_LH_REPTR         (1 << 9)    /**< RXER pin reset latch value */
+#define DM9161A_LH_TSTMOD        (1 << 8 )   /**< RXDV pin reset latch value */
+#define DM9161A_LH_OP2           (1 << 7 )   /**< LINKLED pin reset latch value */
+#define DM9161A_LH_OP1           (1 << 6 )   /**< SPOLED pin reset latch value */
+#define DM9161A_LH_OP0           (1 << 5 )   /**< FDXLED pin reset latch value */
+#define DM9161A_LH_PH4           (1 << 4 )   /**< CRS pin reset latch value */
+#define DM9161A_LH_PH3           (1 << 3 )   /**< RXD3 pin reset latch value */
+#define DM9161A_LH_PH2           (1 << 2 )   /**< RXD2 pin reset latch value */
+#define DM9161A_LH_PH1           (1 << 1 )   /**< RXD1 pin reset latch value */
+#define DM9161A_LH_PH0           (1 << 0 )   /**< RXD0 pin reset latch value */
+
+#define DM9161A_FULLD_100M        0x2100      /**< Full Duplex 100Mbit               */
+#define DM9161A_HALFD_100M        0x2000      /**< Half Duplex 100Mbit               */
+#define DM9161A_FULLD_10M         0x0100      /**< Full Duplex 10Mbit                */
+#define DM9161A_HALFD_10M         0x0000      /**< Half Duplex 10MBit                */
+#define DM9161A_AUTO_NEG          0x3000      /**< Select Auto Negotiation           */
+#define DM9161A_AUTO_NEG_MASK     0xEFFF      /**< Auto Negotiation mask bit         */
+
+/** \brief DM9161A PHY ID register definitions */
+#define DM9161A_PHYID1_OUI        0x0181      /**< Expected PHY ID1 */
+#define DM9161A_PHYID2_OUI        0xB8A0      /**< Expected PHY ID2 */
+
+#define DM9161A_DEF_ADR           0x1300      /**< Default PHY device address DM9161A */
+
+/** \brief PHY status structure used to indicate current status of PHY.
+ */
+typedef struct {
+    u32_t     phy_speed_100mbs:2; /**< 10/100 MBS connection speed flag. */
+    u32_t     phy_full_duplex:2;  /**< Half/full duplex connection speed flag. */
+    u32_t     phy_link_active:2;  /**< Phy link active flag. */
+} PHY_STATUS_TYPE;
+
+/** \brief  PHY update flags */
+static PHY_STATUS_TYPE physts;
+
+/** \brief  Last PHY update flags, used for determing if something has changed */
+static PHY_STATUS_TYPE olddphysts;
+
+/** \brief  PHY update counter for state machine */
+static s32_t phyustate;
+
+/** \brief  Update PHY status from passed value
+ *
+ *  This function updates the current PHY status based on the
+ *  passed PHY status word. The PHY status indicate if the link
+ *  is active, the connection speed, and duplex.
+ *
+ *  \param[in]    netif   NETIF structure
+ *  \param[in]    linksts Status word with link state
+ *  \param[in]    sdsts   Status word with speed and duplex states
+ *  \return        1 if the status has changed, otherwise 0
+ */
+static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts, u32_t sdsts)
+{
+    s32_t changed = 0;
+
+//    sdsts &= DM9161A_AUTO_NEG_MASK; // mask DM9161A_AUTO_NEG
+
+    /* Update link active status */
+    if (linksts & DM9161A_LINK_STATUS)
+        physts.phy_link_active = 1;
+    else
+        physts.phy_link_active = 0;
+
+    /* Full or half duplex */
+    if (sdsts & DM9161A_DUPLEX_MODE)
+        physts.phy_full_duplex = 1;
+    else
+        physts.phy_full_duplex = 0;
+
+    /* Configure 100MBit/10MBit mode. */
+    if (sdsts & DM9161A_SPEED_SELECT)
+        physts.phy_speed_100mbs = 1;
+    else
+        physts.phy_speed_100mbs = 0;
+
+    if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
+        changed = 1;
+        if (physts.phy_speed_100mbs) {
+            /* 100MBit mode. */
+            lpc_emac_set_speed(1);
+
+            NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
+        }
+        else {
+            /* 10MBit mode. */
+            lpc_emac_set_speed(0);
+
+            NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
+        }
+
+        olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
+    }
+
+    if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
+        changed = 1;
+        if (physts.phy_full_duplex)
+            lpc_emac_set_duplex(1);
+        else
+            lpc_emac_set_duplex(0);
+
+        olddphysts.phy_full_duplex = physts.phy_full_duplex;
+    }
+
+    if (physts.phy_link_active != olddphysts.phy_link_active) {
+        changed = 1;
+#if NO_SYS == 1
+        if (physts.phy_link_active)
+            netif_set_link_up(netif);
+        else
+            netif_set_link_down(netif);
+#else
+        if (physts.phy_link_active)
+            tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
+                (void*) netif, 1);
+         else
+            tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
+                (void*) netif, 1);
+#endif
+
+        olddphysts.phy_link_active = physts.phy_link_active;
+    }
+
+    return changed;
+}
+
+/** \brief  Initialize the DM9161A PHY.
+ *
+ *  This function initializes the DM9161A PHY. It will block until
+ *  complete. This function is called as part of the EMAC driver
+ *  initialization. Configuration of the PHY at startup is
+ *  controlled by setting up configuration defines in lpc_phy.h.
+ *
+ *  \param[in]     netif   NETIF structure
+ *  \param[in]     rmii    If set, configures the PHY for RMII mode
+ *  \return         ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
+ */
+err_t lpc_phy_init(struct netif *netif, int rmii)
+{
+    u32_t tmp;
+    s32_t i;
+
+    physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 2;
+    physts.phy_full_duplex = olddphysts.phy_full_duplex = 2;
+    physts.phy_link_active = olddphysts.phy_link_active = 2;
+    phyustate = 0;
+
+    /* Only first read and write are checked for failure */
+    /* Put the DM9161A in reset mode and wait for completion */
+    if (lpc_mii_write(DM9161A_BMCR_REG, DM9161A_RESET) != 0)
+        return ERR_TIMEOUT;
+    i = 400;
+    while (i > 0) {
+        osDelay(1);   // 1 ms
+        if (lpc_mii_read(DM9161A_BMCR_REG, &tmp) != 0)
+            return ERR_TIMEOUT;
+
+        if (!(tmp & (DM9161A_RESET | DM9161A_POWER_DOWN)))
+            i = -1;
+        else
+            i--;
+    }
+    // Timeout?
+    if (i == 0)
+        return ERR_TIMEOUT;
+
+    /* Setup link based on configuration options */
+#if PHY_USE_AUTONEG==1
+    tmp = DM9161A_AUTONEG | DM9161A_RESTART_AUTONEG;
+#else
+    tmp = 0;
+#endif 
+#if PHY_USE_100MBS==1
+    tmp |= DM9161A_SPEED_SELECT;
+#endif
+#if PHY_USE_FULL_DUPLEX==1
+    tmp |= DM9161A_DUPLEX_MODE;
+#endif
+
+    lpc_mii_write(DM9161A_BMCR_REG, tmp);
+
+    /* Enable RMII mode for PHY  - NOT NEEDED FOR MIDI-DK - RMII pin is lathed on reset*/
+/*    if (rmii)
+        lpc_mii_write(DM9161A_DSCR_REG, DM9161A_RMII_ENABLE);
+*/
+    /* The link is not set active at this point, but will be detected
+       later */
+
+    return ERR_OK;
+}
+
+/* Phy status update state machine */
+s32_t lpc_phy_sts_sm(struct netif *netif)
+{
+    static u32_t sts;
+    s32_t changed = 0;
+    switch (phyustate)
+    {
+        default:
+        case 0:
+            // Read BMSR to clear faults
+            lpc_mii_read_noblock(DM9161A_BMSR_REG);
+            phyustate = 1;
+            break;
+
+        case 1:
+            // Wait for read status state
+            if (!lpc_mii_is_busy())
+            {
+                // Get autonegotiation complete bit
+                sts = lpc_mii_read_data();
+                lpc_mii_read_noblock(DM9161A_BMCR_REG);
+                phyustate = 2;
+            }
+            break;
+
+        case 2:
+            // Wait for read status state
+            if (!lpc_mii_is_busy())
+            {
+                // Update PHY status (BMCR contains speed and duplex state)
+                changed = lpc_update_phy_sts(netif, sts, lpc_mii_read_data());
+                phyustate = 0;
+            }
+            break;
+    }
+    return changed;
+}
+
+/* //Original state machine code
+*/
+
+
+
+/**
+ * @}
+ */
+
+/* --------------------------------- End Of File ------------------------------ */