为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

LPC1768以太网控制器

2017-09-30 18页 doc 45KB 50阅读

用户头像

is_511210

暂无简介

举报
LPC1768以太网控制器LPC1768以太网控制器 本文记录LPC1768的以太网控制器学习使用心得。网卡芯片以DP83848C为例。主芯片内的以太网控制器(EMAC)位于ISO模型中的数据链路层,而外围网卡(PHY)位于ISO模型中的物理层。这两者通过RMII(简化的媒体独立接口)连接这样就可以一个简单的以太网通信了。下面通过分析函数来了解相应的知识。分析LPC1768的例程。 、控制器初始化函数。 Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct) { /* Initialize the ...
LPC1768以太网控制器
LPC1768以太网控制器 本文LPC1768的以太网控制器学习使用心得。网卡芯片以DP83848C为例。主芯片内的以太网控制器(EMAC)位于ISO模型中的数据链路层,而外围网卡(PHY)位于ISO模型中的物理层。这两者通过RMII(简化的媒体独立接口)连接这样就可以一个简单的以太网通信了。下面通过分析函数来了解相应的知识。分析LPC1768的例程。 <一>、控制器初始化函数。 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); //(1)打开以太网控制器 /* 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; //(2)置位MAC1配置寄存器中的一些位。 LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;//(3)复位控制命令寄存器 /* A short delay after reset. */ for (tout = 100; tout; tout--); /* Initialize MAC control registers. */ LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; //允许所有的帧信息传送,包括常规帧和控制帧,使能接收功能时生效 LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN; //允许填充短帧,添加CRC LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; //帧最大长度为1536 /* * Find the clock that close to desired target clock */ tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK; for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){ if (EMAC_clkdiv[tout] >= tmp) break; } tout++; // Write to MAC configuration register and reset LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII; //设置MII的AHB总线时钟分频数,复位MII // release reset LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII); //释放MII复位 LPC_EMAC->CLRT = EMAC_CLRT_DEF; // 设置冲突后重发次数和冲突时间槽 LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF; //设置非连续包时间间隔 /* Enable Reduced MII interface. */ LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM; //将MAC设置为RMII模式并设置可接收短帧 /* Reset Reduced MII Logic. */ LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII; //未定义? for (tout = 100; tout; tout--); LPC_EMAC->SUPP = 0; //PHY支持寄存器,操作速率将为10M(10/100M) /* Put the DP83848C in reset mode */ write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET); //(4) /* 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); } } // Set PHY mode if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){ //(5)设置PHY模式,mode为自动模式 return (ERROR); } // Set EMAC address setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr); //设置MAC地址 /* Initialize Tx and Rx DMA Descriptors */ rx_descr_init (); //(6) tx_descr_init (); //发射通道初始化,同理6 // Set Receive Filter register: enable broadcast and multicast LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN; //RxFilterCtrl接收过滤控制寄存器,接收多播帧,接收广播帧,接收和MAC地址相同的帧 /* 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; //MAC寄存器中接收使能 return SUCCESS; } (1)CLKPWR_ConfigPPWR函数将设置外设功率控制寄存器(PCONP),以打开或者关闭相应的外设的时钟源。 (2)复位的这些位定义如下, #define EMAC_MAC1_RES_TX 0x00000100 /**< Reset TX Logic该位置位将使发送功能逻辑进入复位状态*/ #define EMAC_MAC1_RES_MCS_TX 0x00000200 /**< Reset MAC TX Control Sublayer,MAC层的发送逻辑复位MCS执行流控制*/ #define EMAC_MAC1_RES_RX 0x00000400 /**< Reset RX Logic该位置位将使接受功能逻辑进入复位状态*/ #define EMAC_MAC1_RES_MCS_RX 0x00000800 /**< Reset MAC RX Control Sublayer,MAC层的接受逻辑复位MCS执行流控制*/ #define EMAC_MAC1_SIM_RES 0x00004000 /**< Simulation Reset发送功能中的随机数发生器复位*/ #define EMAC_MAC1_SOFT_RES 0x00008000 /**< Soft Reset MAC 将使MAC中的除主机接口的所有状态复位*/ (3)定义如下 #define EMAC_CR_REG_RES 0x00000008 /**< Reset Host Registers 所有的通道和和主机寄存器都复位*/ #define EMAC_CR_TX_RES 0x00000010 /**< Reset Transmit Datapath 复位发送通道 */ #define EMAC_CR_RX_RES 0x00000020 /**< Reset Receive Datapath 复位接收通道*/ #define EMAC_CR_PASS_RUNT_FRM 0x00000040 /**< Pass Runt Frames 接收短帧功能 */ (4)这个函数是写数据到外部网卡(PHY)的。 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value) //PhyReg,PHY中寄存器地址 value,值 { /* Write a data 'Value' to PHY register 'PhyReg'. */ uint32_t tout; LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; //EMAC_DEF_ADR是默认的PHY(最多可控制32个PHY)。MADR里包含哪个PHY哪个寄存器 LPC_EMAC->MWTD = Value; //寄存器的值 /* Wait until operation completed */ tout = 0; for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) { //等待操作结束 if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { return (0); } } // Time out! return (-1); } (5) int32_t EMAC_SetPHYMode(uint32_t ulPHYMode) { int32_t id1, id2, tout, regv; /* Check if this is a DP83848C PHY. */ id1 = read_PHY (EMAC_PHY_REG_IDR1); //读出PHY芯片的ID id2 = read_PHY (EMAC_PHY_REG_IDR2); #ifdef MCB_LPC_1768 if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) { //ID是DP8384的ID switch(ulPHYMode){ //根据参数进入相应的部分设置PHY case EMAC_MODE_AUTO: write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); //设置PHY的Base Control寄存器的位为自动选择传输速率和方式 #elif defined(IAR_LPC_1768) /* Use IAR LPC1768 KickStart board */ if (((id1 << 16) | id2) == EMAC_KSZ8721BL_ID) { /* Configure the PHY device */ switch(ulPHYMode){ case EMAC_MODE_AUTO: /* Use auto-negotiation about the link speed. */ write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); // write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_AN); #endif /* Wait to complete Auto_Negotiation */ for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { regv = read_PHY (EMAC_PHY_REG_BMSR); if (regv & EMAC_PHY_BMSR_AUTO_DONE) { /* Auto-negotiation Complete. */ break; } if (tout == 0){ // Time out, return error return (-1); } } break; case EMAC_MODE_10M_FULL: /* Connect at 10MBit full-duplex */ write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M); break; case EMAC_MODE_10M_HALF: /* Connect at 10MBit half-duplex */ write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M); break; case EMAC_MODE_100M_FULL: /* Connect at 100MBit full-duplex */ write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M); break; case EMAC_MODE_100M_HALF: /* Connect at 100MBit half-duplex */ write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M); break; default: // un-supported return (-1); } } // It's not correct module ID else { return (-1); } // Update EMAC configuration with current PHY status if (EMAC_UpdatePHYStatus() < 0){ //这个函数会读取PHY中的0x10寄存器来查出现在PHY的速率和传输方式,来设置MAC的速率和传输方式 return (-1); } // Complete return (0); } (6) static void rx_descr_init (void) { /* Initialize Receive Descriptor and Status array. */ uint32_t i; for (i = 0; i < EMAC_NUM_RX_FRAG; i++) { Rx_Desc[i].Packet = (uint32_t)&rx_buf[i]; //<1> Rx_Desc[i].Ctrl = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1); //控制字段 Rx_Stat[i].Info = 0; Rx_Stat[i].HashCRC = 0; } /* Set EMAC Receive Descriptor Registers. */ LPC_EMAC->RxDescriptor = (uint32_t)&Rx_Desc[0]; //RxDescriptor保存接收描述符数组的基地址(最低地址) LPC_EMAC->RxStatus = (uint32_t)&Rx_Stat[0]; //RxStatus LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1; //接收描述符数目寄存器 /* Rx Descriptors Point to 0 */ LPC_EMAC->RxConsumeIndex = 0; //接收消耗索引,它与RxProductIndex(接收生产索引)组成环状缓存形式 } <1>rx_buf是一个二维数组,4个接收数据数组,每个1536字节 如:static uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2]; :EMAC_Init函数初始化了了以太网模块中的各个寄存器并通过其设置了外部的PHY,为收发数据做好了准备。 <二> 之后程序打开了设置了各个变量后,调用函数 void DoNetworkStuff(void) { if (CheckFrameReceived()) // 函数将检查RxConsumeIndex和RxProductIndex是否相等来判断是否有数据来 { if (IsBroadcast()) { //(1) ProcessEthBroadcastFrame(); //广播消息的处理 } else { ProcessEthIAFrame(); //处理ARP帧和IP帧,本文不深入协议部分。 } EndReadFrame(); //设置消耗索引RxConsumeIndex,即++,若索引到尽头,因为是环形缓冲,所以索引置0 } if (TCPFlags & TCP_TIMER_RUNNING) if (TCPFlags & TIMER_TYPE_RETRY) { if (TCPTimer > RETRY_TIMEOUT) { TCPRestartTimer(); // set a new timeout if (RetryCounter) { TCPHandleRetransmission(); // resend last frame RetryCounter--; } else { TCPStopTimer(); TCPHandleTimeout(); } } } else if (TCPTimer > FIN_TIMEOUT) { TCPStateMachine = CLOSED; TCPFlags = 0; // reset all flags, stop retransmission... SocketStatus &= SOCK_DATA_AVAILABLE; // clear all flags but data available } switch (TCPStateMachine) { case CLOSED : case LISTENING : { if (TCPFlags & TCP_ACTIVE_OPEN) // stack has to open a connection? if (TCPFlags & IP_ADDR_RESOLVED) // IP resolved? if (!(TransmitControl & SEND_FRAME2)) // buffer free? { TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (SysTick->VAL & 0xFFFF); // NXP: changed from T0TC to SysTick->VAL; // set local ISN TCPUNASeqNr = TCPSeqNr; TCPAckNr = 0; // we don't know what to ACK! TCPUNASeqNr++; // count SYN as a byte PrepareTCP_FRAME(TCP_CODE_SYN); // send SYN frame LastFrameSent = TCP_SYN_FRAME; TCPStartRetryTimer(); // we NEED a retry-timeout TCPStateMachine = SYN_SENT; } break; } case SYN_RECD : case ESTABLISHED : { if (TCPFlags & TCP_CLOSE_REQUESTED) // user has user initated a close? if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1))) // buffers free? if (TCPSeqNr == TCPUNASeqNr) // all data ACKed? { TCPUNASeqNr++; PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK); LastFrameSent = TCP_FIN_FRAME; TCPStartRetryTimer(); TCPStateMachine = FIN_WAIT_1; } break; } case CLOSE_WAIT : { if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1))) // buffers free? if (TCPSeqNr == TCPUNASeqNr) // all data ACKed? { TCPUNASeqNr++; // count FIN as a byte PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK); // we NEED a retry-timeout LastFrameSent = TCP_FIN_FRAME; // time to say goodbye... TCPStartRetryTimer(); TCPStateMachine = LAST_ACK; } break; } } if (TransmitControl & SEND_FRAME2) { RequestSend(TxFrame2Size); if (Rdy4Tx()) { // NOTE: when using a very fast MCU, maybe _DBG_("Send Frm2"); SendFrame2(); // the EMAC isn't ready yet, include } else { // a kind of timer or counter here TCPStateMachine = CLOSED; SocketStatus = SOCK_ERR_ETHERNET; // indicate an error to user TCPFlags = 0; // clear all flags, stop timers etc. } TransmitControl &= ~SEND_FRAME2; // clear tx-flag } if (TransmitControl & SEND_FRAME1) { PrepareTCP_DATA_FRAME(); // build frame w/ actual SEQ, ACK.... RequestSend(TxFrame1Size); if (Rdy4Tx()){ // EMAC ready to accept our frame? _DBG_("Send Frm1"); SendFrame1(); // (see note above) } else { TCPStateMachine = CLOSED; SocketStatus = SOCK_ERR_ETHERNET; // indicate an error to user TCPFlags = 0; // clear all flags, stop timers etc. } TransmitControl &= ~SEND_FRAME1; // clear tx-flag } } (1) unsigned int IsBroadcast(void) { unsigned short RecdDestMAC[3]; // 48 bit MAC RecdFrameLength = StartReadFrame(); //<1> CopyFromFrame_EMAC(&RecdDestMAC, 6); //此函数从rptr中顺序读取6个字节到 RecdDestMAC,这首6个字节是目标MAC地址 CopyFromFrame_EMAC(&RecdFrameMAC, 6); //再读6个字节到RecdFrameMAC,是源MAC地址 if ((RecdDestMAC[0] == 0xFFFF) && //如果MAC地址是0xFFFFFFFFFFFF就是广播地址 (RecdDestMAC[1] == 0xFFFF) && (RecdDestMAC[2] == 0xFFFF)) { return(1); } else { return (0); } } <1> unsigned short StartReadFrame(void) { unsigned short RxLen; EMAC_PACKETBUF_Type RxPack; RxLen = EMAC_GetReceiveDataSize() - 3; //函数将通过状态寄存器中保存的状态变量地址中的info字段来判断帧的长度 // Copy packet to data buffer RxPack.pbDataBuf = (uint32_t *)pgBuf; //pgBuf = LPC_AHBRAM1_BASE,这是一块未使用的地址,可用来保存接收的帧数据 RxPack.ulDataLen = RxLen; EMAC_ReadPacketBuffer(&RxPack); //从寄存器指向的环形缓冲中,拷贝一帧数据到pgBuf // Point to the data buffer rptr = (unsigned short *)pgBuf; //用全局rptr变量保存地址 return(RxLen); } 第二节,分析和协议相关部分 如果不是广播包,则调用函数 void ProcessEthIAFrame(void) { unsigned short TargetIP[2]; unsigned char ProtocolType; switch (ReadFrameBE_EMAC()) // get frame type 读取类型字段 { case FRAME_ARP : // check for ARP { if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN) if (ReadFrameBE_EMAC() == HARDW_ETH10) // check for the right prot. etc. if (ReadFrameBE_EMAC() == FRAME_IP) if (ReadFrameBE_EMAC() == IP_HLEN_PLEN) if (ReadFrameBE_EMAC() == OP_ARP_ANSWER) { TCPStopTimer(); // OK, now we've the MAC we wanted ;-) CopyFromFrame_EMAC(&RemoteMAC, 6); // extract opponents MAC TCPFlags |= IP_ADDR_RESOLVED; } break; } case FRAME_IP : // check for IP-type { if ((ReadFrameBE_EMAC() & 0xFF00 ) == IP_VER_IHL) // IPv4, IHL=5 (20 Bytes Header) { // ignore Type Of Service RecdIPFrameLength = ReadFrameBE_EMAC(); // get IP frame's length ReadFrameBE_EMAC(); // ignore identification if (!(ReadFrameBE_EMAC() & (IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK))) // only unfragm. frames { ProtocolType = ReadFrameBE_EMAC() & 0xFF; // get protocol, ignore TTL ReadFrameBE_EMAC(); // ignore checksum CopyFromFrame_EMAC(&RecdFrameIP, 4); // get source IP CopyFromFrame_EMAC(&TargetIP, 4); // get destination IP if (!memcmp(&MyIP, &TargetIP, 4)) // is it for us? switch (ProtocolType) { case PROT_ICMP : { ProcessICMPFrame(); break; } case PROT_TCP : { ProcessTCPFrame(); break; } case PROT_UDP : break; // not implemented! } } } break; } } }
/
本文档为【LPC1768以太网控制器】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索