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.
Diff: lpc_phy_DM9161A.c
- Revision:
- 0:6901daab33f0
- Child:
- 2:e8cdfd3c70f5
--- /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 ------------------------------ */