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.
lpc_phy_DM9161A.c
- Committer:
- frankvnk
- Date:
- 2013-03-18
- Revision:
- 2:e8cdfd3c70f5
- Parent:
- 0:6901daab33f0
File content as of revision 2:e8cdfd3c70f5:
/********************************************************************** * $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); /* Wait for autonegotiation completion */ i = 400; while (i > 0) { osDelay(1); // 1 ms if (lpc_mii_read(DM9161A_BMSR_REG, &tmp) != 0) { printf("Timeout\n"); return ERR_TIMEOUT; } if (tmp & (DM9161A_AUTONEG_COMP)) i = -1; else i--; } // Timeout? if (i == 0) { printf("Timeout\n"); return ERR_TIMEOUT; } /* 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 ------------------------------ */