报告3 ——以太网TCP Server 1. 总结利用官方的uIP+EMAC的例程研究了一段时间,无论如何也不能正确的建立连接,经过研究发现了几点不同需要特别注意: 1、 LPC1768主板采用的Phy为KSZ8001L; 2、 设计上增加了以太网芯片的电源控制; 注意到这两点,问题基本扫清了。 2. 硬件连接关系和引脚初始化
硬件上的连接除了RMII要求的引脚必须初始化外,特别需要提醒的是上图中红色圈出的部分,P1.29 ETH_PHY_PD的引脚,这个引脚是KSZ8001L的Power Down控制引脚,通常的驱动中不会特殊提到这个引脚的使用,根据手册中的描述,这个引脚应该初始化为GPIO的输出模式,并且因该拉高,使能物理层的正常工作。
我之前一直没有注意到,导致调试了好几天都没有进展。
- /*
- * Enable P1 Ethernet Pins:
- * P1.0 - ENET_TXD0
- * P1.1 - ENET_TXD1
- * P1.4 - ENET_TX_EN
- * P1.8 - ENET_CRS
- * P1.9 - ENET_RXD0
- * P1.10 - ENET_RXD1
- * P1.14 - ENET_RX_ER
- * P1.15 - ENET_REF_CLK
- * P1.16 - ENET_MDC
- * P1.17 - ENET_MDIO
- */
- PinCfg.Funcnum = 1;
- PinCfg.OpenDrain = 0;
- PinCfg.Pinmode = 0;
- PinCfg.Portnum = 1;
- PinCfg.Pinnum = 0;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 1;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 4;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 8;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 9;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 10;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 14;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 15;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 16;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 17;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = 29;
- PinCfg.Funcnum = 0;
- PINSEL_ConfigPin(&PinCfg);
- GPIO_SetDir(1, (1<<29), 1);
- GPIO_SetValue(1, (1<<29));
复制代码 3. 物理层初始化在驱动移植过程中,特别要注意的一个地方是: #defineEMAC_DEF_ADR (0x00<<8) /**< Default PHY deviceaddress */ 这个是用于EMAC读写物理层寄存器时使用。 - Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
- {
- /* Initialize the EMAC Ethernet controller. */
- int32_t regv,tout, tmp;
- /* Set up clock and power for Ethernet module */
- CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);
- delay_ms(100);
- /* Reset all EMAC internal modules */
- LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX |
- EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES |EMAC_MAC1_RX_FLOWC | EMAC_MAC1_TX_FLOWC;
- LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES;
- /* A short delay after reset. */
- delay_ms(1);
- /* Initialize MAC control registers. */
- LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
- LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN;
- LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
- LPC_EMAC->CLRT = EMAC_CLRT_DEF;
- LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
- /*
- * Find the clock that close to desired target clock
- */
- // host clock divided by 28, no suppress preamble, no scan increment
- // TBD: Should this be calculated at run time?
- LPC_EMAC->MCFG = 0x801C;
- delay_ms(10);
- // release reset
- LPC_EMAC->MCFG = 0x0018;
- LPC_EMAC->MCMD = 0;
- /* Enable Reduced MII interface. */
- LPC_EMAC->Command = EMAC_CR_RMII;// | EMAC_CR_PASS_RUNT_FRM;
- LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
- delay_ms(100);
- /* Put the DP83848C in reset mode */
- write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET);
- delay_ms(1000);
- /* Wait for hardware reset to end. */
- for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
- regv = read_PHY (EMAC_PHY_REG_BMCR);
- if (!(regv & (EMAC_PHY_BMCR_RESET))) { // | EMAC_PHY_BMCR_POWERDOWN
- /* Reset complete, device not Power Down. */
- break;
- }
- if (tout == 0){
- // Time out, return ERROR
- return (ERROR);
- }
- }
- // Setup PAUSE control (PAUSE and ASM_DIR in ANAR register)
- regv = read_PHY(EMAC_PHY_REG_ANAR);
- write_PHY(EMAC_PHY_REG_ANAR, regv|(1<<10)|(1<<11));
-
- // Set PHY mode
- if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){
- return (ERROR);
- }
- // Set EMAC address
- setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
- /* Initialize Tx and Rx DMA Descriptors */
- rx_descr_init ();
- tx_descr_init ();
- // Set Receive Filter register: enable broadcast and multicast
- LPC_EMAC->RxFilterCtrl = EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
- /* Enable Rx Done and Tx Done interrupt for EMAC */
- LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE;
- /* Reset all interrupts */
- LPC_EMAC->IntClear = 0xFFFF;
- /* Enable receive and transmit mode of MAC Ethernet core */
- LPC_EMAC->Command |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN);
- LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
- return SUCCESS;
- }
- 原有驱动时基于83848的,改成KSZ8001L还是有调整的。
复制代码 4. 基于uIP的TCPServer物理层初始化完成,接就是TCP/IP协议栈的移植,这里采用uIP。 协议栈的初始化过程,包括uip的初始化,本机IP地址,子网掩码,网关的初始化。结束后基本具备了通讯条件。 4.1. TCPServer初始化void mytcp_init(void) { /*We start to listen for connections on TCP port 1000. */ uip_listen(HTONS(1000)); } 这个时初始化TCPServer监听端口号为1000的端口。 4.2. 数据获取处理和发送uIP有一个关键函数uip_appcall(),所有的用户数据处理都在这里完成。 void mytcp_appcall(void) { /* *The uip_conn structure has a field called "appstate" that holds *the application state of the connection. We make a pointer to *this to access it easier. */ structmytcp_state *s = &(uip_conn->appstate); intlen,i; char*nptr; /* *If a new connection was just established, we should initialize *the protosocket in our applications' state structure. */ if(uip_connected()) { PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer)); } if(uip_conn->lport == HTONS(6000)) { if(uip_newdata()) { len=uip_datalen(); nptr=(char*)uip_appdata; if(len< UIP_SEND_BUF_MAX_LEN) { nptr[len]= 0; uip_send(nptr,len); } } } } 通过uip_conn->lport == HTONS(6000)判定连接上发来的数据来自我们监听的端口,这个方法可以保证当监听多个端口时,仍然可以区分数据的来源。 uip_newdata()函数判断uIP协议栈已经获取了有效的数据输入。 len=uip_datalen();获取输入有效数据的长度。 nptr=(char*)uip_appdata;取得接收到的数据。 5. 效果展示
初始化 收到数据后原样回传测试 以太网通道建立完成,下一步时通过以太网通道完成DEV板载接口的控制。
|