Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
lm3s_eth.c
Go to the documentation of this file.
00001 /** 00002 * @file lm3s_eth.c 00003 * @brief Luminary Stellaris LM3S Ethernet controller 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL NIC_TRACE_LEVEL 00031 00032 //LM3S6965 device? 00033 #if defined(LM3S6965) 00034 #include "lm3s6965.h" 00035 //LM3S9B92 device? 00036 #elif defined(LM3S9B92) 00037 #include "lm3s9b92.h" 00038 #endif 00039 00040 //Dependencies 00041 #include "inc/hw_ints.h" 00042 #include "inc/hw_memmap.h" 00043 #include "inc/hw_types.h" 00044 #include "driverlib/gpio.h" 00045 #include "driverlib/interrupt.h" 00046 #include "driverlib/sysctl.h" 00047 #include "core/net.h" 00048 #include "drivers/lm3s_eth.h" 00049 #include "debug.h" 00050 00051 //Underlying network interface 00052 static NetInterface *nicDriverInterface; 00053 00054 //IAR EWARM compiler? 00055 #if defined(__ICCARM__) 00056 00057 //Transmit buffer 00058 #pragma data_alignment = 4 00059 static uint8_t txBuffer[ETH_MAX_FRAME_SIZE + 2]; 00060 //Receive buffer 00061 #pragma data_alignment = 4 00062 static uint8_t rxBuffer[ETH_MAX_FRAME_SIZE]; 00063 00064 //Keil MDK-ARM or GCC compiler? 00065 #else 00066 00067 //Transmit buffer 00068 static uint8_t txBuffer[ETH_MAX_FRAME_SIZE + 2] __attribute__((aligned(4))); 00069 //Receive buffer 00070 static uint8_t rxBuffer[ETH_MAX_FRAME_SIZE] __attribute__((aligned(4))); 00071 00072 #endif 00073 00074 00075 /** 00076 * @brief Stellaris LM3S Ethernet driver 00077 **/ 00078 00079 const NicDriver lm3sEthDriver = 00080 { 00081 NIC_TYPE_ETHERNET, 00082 ETH_MTU, 00083 lm3sEthInit, 00084 lm3sEthTick, 00085 lm3sEthEnableIrq, 00086 lm3sEthDisableIrq, 00087 lm3sEthEventHandler, 00088 lm3sEthSendPacket, 00089 lm3sEthSetMulticastFilter, 00090 NULL, 00091 NULL, 00092 NULL, 00093 TRUE, 00094 TRUE, 00095 TRUE, 00096 FALSE 00097 }; 00098 00099 00100 /** 00101 * @brief Stellaris LM3S Ethernet controller initialization 00102 * @param[in] interface Underlying network interface 00103 * @return Error code 00104 **/ 00105 00106 error_t lm3sEthInit(NetInterface *interface) 00107 { 00108 uint_t div; 00109 00110 //Debug message 00111 TRACE_INFO("Initializing Stellaris LM3S Ethernet controller...\r\n"); 00112 00113 //Save underlying network interface 00114 nicDriverInterface = interface; 00115 00116 //Enable Ethernet controller clock 00117 SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH); 00118 //Reset Ethernet controller 00119 SysCtlPeripheralReset(SYSCTL_PERIPH_ETH); 00120 00121 //GPIO configuration 00122 lm3sEthInitGpio(interface); 00123 00124 //The MDC clock frequency cannot exceed 2.5MHz 00125 div = SysCtlClockGet() / (2 * 2500000) - 1; 00126 //Adjust MDC clock frequency 00127 MAC_MDV_R = div & MAC_MDV_DIV_M; 00128 00129 //Reset PHY transceiver 00130 lm3sEthWritePhyReg(PHY_MR0, PHY_MR0_RESET); 00131 //Wait for the reset to complete 00132 while(lm3sEthReadPhyReg(PHY_MR0) & PHY_MR0_RESET); 00133 00134 //Dump PHY registers for debugging purpose 00135 lm3sEthDumpPhyReg(); 00136 00137 //Configure LED0 and LED1 00138 lm3sEthWritePhyReg(PHY_MR23, PHY_MR23_LED0_RXTX | PHY_MR23_LED1_LINK); 00139 00140 //Set the MAC address 00141 MAC_IA0_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16); 00142 MAC_IA1_R = interface->macAddr.w[2]; 00143 00144 //Enable automatic CRC generation and packet padding 00145 MAC_TCTL_R = MAC_TCTL_DUPLEX | MAC_TCTL_CRC | MAC_TCTL_PADEN; 00146 //Flush the receive FIFO and enable CRC verification 00147 MAC_RCTL_R = MAC_RCTL_RSTFIFO | MAC_RCTL_BADCRC; 00148 00149 //Configure Ethernet interrupts 00150 MAC_IM_R = MAC_IM_PHYINTM | MAC_IM_TXEMPM | MAC_IM_RXINTM; 00151 //Configure PHY interrupts 00152 lm3sEthWritePhyReg(PHY_MR17, PHY_MR17_LSCHG_IE); 00153 00154 //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority) 00155 IntPriorityGroupingSet(LM3S_ETH_IRQ_PRIORITY_GROUPING); 00156 //Configure Ethernet interrupt priority 00157 IntPrioritySet(INT_ETH, LM3S_ETH_IRQ_PRIORITY); 00158 00159 //Enable transmitter 00160 MAC_TCTL_R |= MAC_TCTL_TXEN; 00161 //Enable receiver 00162 MAC_RCTL_R |= MAC_RCTL_RXEN; 00163 00164 //Accept any packets from the upper layer 00165 osSetEvent(&interface->nicTxEvent); 00166 00167 //Successful initialization 00168 return NO_ERROR; 00169 } 00170 00171 00172 //EK-LM3S6965 evaluation board? 00173 #if defined(USE_EK_LM3S6965) 00174 00175 /** 00176 * @brief GPIO configuration 00177 * @param[in] interface Underlying network interface 00178 **/ 00179 00180 void lm3sEthInitGpio(NetInterface *interface) 00181 { 00182 //Enable GPIO clock 00183 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); 00184 00185 //Configure status LEDs 00186 GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3); 00187 } 00188 00189 #endif 00190 00191 00192 /** 00193 * @brief Stellaris LM3S Ethernet timer handler 00194 * 00195 * This routine is periodically called by the TCP/IP stack to 00196 * handle periodic operations such as polling the link state 00197 * 00198 * @param[in] interface Underlying network interface 00199 **/ 00200 00201 void lm3sEthTick(NetInterface *interface) 00202 { 00203 } 00204 00205 00206 /** 00207 * @brief Enable interrupts 00208 * @param[in] interface Underlying network interface 00209 **/ 00210 00211 void lm3sEthEnableIrq(NetInterface *interface) 00212 { 00213 //Enable Ethernet interrupts 00214 IntEnable(INT_ETH); 00215 } 00216 00217 00218 /** 00219 * @brief Disable interrupts 00220 * @param[in] interface Underlying network interface 00221 **/ 00222 00223 void lm3sEthDisableIrq(NetInterface *interface) 00224 { 00225 //Disable Ethernet interrupts 00226 IntDisable(INT_ETH); 00227 } 00228 00229 00230 /** 00231 * @brief Stellaris LM3S Ethernet interrupt service routine 00232 **/ 00233 00234 void ETH_IRQHandler(void) 00235 { 00236 bool_t flag; 00237 uint32_t status; 00238 00239 //Enter interrupt service routine 00240 osEnterIsr(); 00241 00242 //This flag will be set if a higher priority task must be woken 00243 flag = FALSE; 00244 00245 //Read interrupt status register 00246 status = MAC_RIS_R; 00247 00248 //PHY interrupt? 00249 if(status & MAC_RIS_PHYINT) 00250 { 00251 //Disable PHYINT interrupt 00252 MAC_IM_R &= ~MAC_IM_PHYINTM; 00253 00254 //Set event flag 00255 nicDriverInterface->nicEvent = TRUE; 00256 //Notify the TCP/IP stack of the event 00257 flag |= osSetEventFromIsr(&netEvent); 00258 } 00259 00260 //Transmit FIFO empty? 00261 if(status & MAC_RIS_TXEMP) 00262 { 00263 //Acknowledge TXEMP interrupt 00264 MAC_IACK_R = MAC_IACK_TXEMP; 00265 00266 //Check whether the transmit FIFO is available for writing 00267 if(!(MAC_TR_R & MAC_TR_NEWTX)) 00268 { 00269 //Notify the TCP/IP stack that the transmitter is ready to send 00270 flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent); 00271 } 00272 } 00273 00274 //Packet received? 00275 if(status & MAC_RIS_RXINT) 00276 { 00277 //Disable RXINT interrupt 00278 MAC_IM_R &= ~MAC_IM_RXINTM; 00279 00280 //Set event flag 00281 nicDriverInterface->nicEvent = TRUE; 00282 //Notify the TCP/IP stack of the event 00283 flag |= osSetEventFromIsr(&netEvent); 00284 } 00285 00286 //Leave interrupt service routine 00287 osExitIsr(flag); 00288 } 00289 00290 00291 /** 00292 * @brief Stellaris LM3S Ethernet event handler 00293 * @param[in] interface Underlying network interface 00294 **/ 00295 00296 void lm3sEthEventHandler(NetInterface *interface) 00297 { 00298 uint32_t status; 00299 uint16_t value; 00300 00301 //Read interrupt status register 00302 status = MAC_RIS_R; 00303 00304 //PHY interrupt? 00305 if(status & MAC_RIS_PHYINT) 00306 { 00307 //Acknowledge PHYINT interrupt 00308 MAC_IACK_R = MAC_IACK_PHYINT; 00309 //Read PHY interrupt status register 00310 value = lm3sEthReadPhyReg(PHY_MR17); 00311 00312 //Check whether the link state has changed 00313 if(value & PHY_MR17_LSCHG_IE) 00314 { 00315 //Read PHY status register 00316 value = lm3sEthReadPhyReg(PHY_MR1); 00317 00318 //Check link state 00319 if(value & PHY_MR1_LINK) 00320 { 00321 //Read PHY diagnostic register 00322 value = lm3sEthReadPhyReg(PHY_MR18); 00323 00324 //Get current speed 00325 if(value & PHY_MR18_RATE) 00326 { 00327 //100BASE-TX operation 00328 interface->linkSpeed = NIC_LINK_SPEED_100MBPS; 00329 } 00330 else 00331 { 00332 //10BASE-T operation 00333 interface->linkSpeed = NIC_LINK_SPEED_10MBPS; 00334 } 00335 00336 //Get current duplex mode 00337 if(value & PHY_MR18_DPLX) 00338 { 00339 //Full-Duplex mode 00340 interface->duplexMode = NIC_FULL_DUPLEX_MODE; 00341 //Update MAC configuration 00342 MAC_TCTL_R |= MAC_TCTL_DUPLEX; 00343 } 00344 else 00345 { 00346 //Half-Duplex mode 00347 interface->duplexMode = NIC_HALF_DUPLEX_MODE; 00348 //Update MAC configuration 00349 MAC_TCTL_R &= ~MAC_TCTL_DUPLEX; 00350 } 00351 00352 //Update link state 00353 interface->linkState = TRUE; 00354 } 00355 else 00356 { 00357 //Update link state 00358 interface->linkState = FALSE; 00359 } 00360 00361 //Process link state change event 00362 nicNotifyLinkChange(interface); 00363 } 00364 } 00365 00366 //Packet received? 00367 if(status & MAC_RIS_RXINT) 00368 { 00369 //Acknowledge RXINT interrupt 00370 MAC_IACK_R = MAC_IACK_RXINT; 00371 00372 //Process all the pending packets 00373 while(MAC_NP_R & MAC_NP_NPR_M) 00374 { 00375 //Read incoming packet 00376 lm3sEthReceivePacket(interface); 00377 } 00378 } 00379 00380 //Re-enable Ethernet interrupts 00381 MAC_IM_R = MAC_IM_PHYINTM | MAC_IM_TXEMPM | MAC_IM_RXINTM; 00382 } 00383 00384 00385 /** 00386 * @brief Send a packet 00387 * @param[in] interface Underlying network interface 00388 * @param[in] buffer Multi-part buffer containing the data to send 00389 * @param[in] offset Offset to the first data byte 00390 * @return Error code 00391 **/ 00392 00393 error_t lm3sEthSendPacket(NetInterface *interface, 00394 const NetBuffer *buffer, size_t offset) 00395 { 00396 size_t i; 00397 size_t length; 00398 uint32_t *p; 00399 00400 //Retrieve the length of the packet 00401 length = netBufferGetLength(buffer) - offset; 00402 00403 //Check the frame length 00404 if(length < sizeof(EthHeader) || length > ETH_MAX_FRAME_SIZE) 00405 { 00406 //The transmitter can accept another packet 00407 osSetEvent(&interface->nicTxEvent); 00408 //Report an error 00409 return ERROR_INVALID_LENGTH; 00410 } 00411 00412 //Make sure the transmit FIFO is available for writing 00413 if(MAC_TR_R & MAC_TR_NEWTX) 00414 return ERROR_FAILURE; 00415 00416 //Copy user data 00417 netBufferRead(txBuffer + 2, buffer, offset, length); 00418 00419 //The packet is preceded by a 16-bit length field 00420 txBuffer[0] = LSB(length - sizeof(EthHeader)); 00421 txBuffer[1] = MSB(length - sizeof(EthHeader)); 00422 00423 //Point to the beginning of the packet 00424 p = (uint32_t *) txBuffer; 00425 //Compute the length of the packet in 32-bit words 00426 length = (length + 5) / 4; 00427 00428 //Copy packet to transmit FIFO 00429 for(i = 0; i < length; i++) 00430 MAC_DATA_R = p[i]; 00431 00432 //Start transmitting 00433 MAC_TR_R = MAC_TR_NEWTX; 00434 00435 //Data successfully written 00436 return NO_ERROR; 00437 } 00438 00439 00440 /** 00441 * @brief Receive a packet 00442 * @return Error code 00443 **/ 00444 00445 error_t lm3sEthReceivePacket(NetInterface *interface) 00446 { 00447 error_t error; 00448 size_t i; 00449 size_t n; 00450 size_t length; 00451 uint32_t data; 00452 uint16_t *p; 00453 00454 //Make sure the FIFO is not empty 00455 if(MAC_NP_R & MAC_NP_NPR_M) 00456 { 00457 //Read the first word 00458 data = MAC_DATA_R; 00459 //Retrieve the total length of the packet 00460 length = data & 0xFFFF; 00461 00462 //Make sure the length field is valid 00463 if(length > 2) 00464 { 00465 //Point to the beginning of the buffer 00466 p = (uint16_t *) rxBuffer; 00467 00468 //Retrieve the length of the frame 00469 length -= 2; 00470 //Limit the number of data to be read 00471 n = MIN(length, ETH_MAX_FRAME_SIZE); 00472 00473 //Copy the first half word 00474 if(n > 0) 00475 *(p++) = (uint16_t) (data >> 16); 00476 00477 //Copy data from receive FIFO 00478 for(i = 2; i < n; i += 4) 00479 { 00480 //Read a 32-bit word from the FIFO 00481 data = MAC_DATA_R; 00482 //Write the 32-bit to the receive buffer 00483 *(p++) = (uint16_t) data; 00484 *(p++) = (uint16_t) (data >> 16); 00485 } 00486 00487 //Skip the remaining bytes 00488 while(i < length) 00489 { 00490 //Read a 32-bit word from the FIFO 00491 data = MAC_DATA_R; 00492 //Increment byte counter 00493 i += 4; 00494 } 00495 00496 //Valid packet received 00497 error = NO_ERROR; 00498 } 00499 else 00500 { 00501 //Disable receiver 00502 MAC_RCTL_R &= ~MAC_RCTL_RXEN; 00503 //Flush the receive FIFO 00504 MAC_RCTL_R |= MAC_RCTL_RSTFIFO; 00505 //Re-enable receiver 00506 MAC_RCTL_R |= MAC_RCTL_RXEN; 00507 00508 //The packet is not valid 00509 error = ERROR_INVALID_PACKET; 00510 } 00511 } 00512 else 00513 { 00514 //No more data in the receive buffer 00515 error = ERROR_BUFFER_EMPTY; 00516 } 00517 00518 //Check whether a valid packet has been received 00519 if(!error) 00520 { 00521 //Pass the packet to the upper layer 00522 nicProcessPacket(interface, rxBuffer, n); 00523 } 00524 00525 //Return status code 00526 return error; 00527 } 00528 00529 00530 /** 00531 * @brief Configure multicast MAC address filtering 00532 * @param[in] interface Underlying network interface 00533 * @return Error code 00534 **/ 00535 00536 error_t lm3sEthSetMulticastFilter(NetInterface *interface) 00537 { 00538 uint_t i; 00539 bool_t acceptMulticast; 00540 00541 //This flag will be set if multicast addresses should be accepted 00542 acceptMulticast = FALSE; 00543 00544 //The MAC filter table contains the multicast MAC addresses 00545 //to accept when receiving an Ethernet frame 00546 for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++) 00547 { 00548 //Valid entry? 00549 if(interface->macMulticastFilter[i].refCount > 0) 00550 { 00551 //Accept multicast addresses 00552 acceptMulticast = TRUE; 00553 //We are done 00554 break; 00555 } 00556 } 00557 00558 //Enable the reception of multicast frames if necessary 00559 if(acceptMulticast) 00560 MAC_RCTL_R |= MAC_RCTL_AMUL; 00561 else 00562 MAC_RCTL_R &= ~MAC_RCTL_AMUL; 00563 00564 //Successful processing 00565 return NO_ERROR; 00566 } 00567 00568 00569 /** 00570 * @brief Write PHY register 00571 * @param[in] address PHY register address 00572 * @param[in] data Register value 00573 **/ 00574 00575 void lm3sEthWritePhyReg(uint8_t address, uint16_t data) 00576 { 00577 //Data to be written in the PHY register 00578 MAC_MTXD_R = data & MAC_MTXD_MDTX_M; 00579 //Start a write operation 00580 MAC_MCTL_R = (address << 3) | MAC_MCTL_WRITE | MAC_MCTL_START; 00581 00582 //Wait for the write to complete 00583 while(MAC_MCTL_R & MAC_MCTL_START); 00584 } 00585 00586 00587 /** 00588 * @brief Read PHY register 00589 * @param[in] address PHY register address 00590 * @return Register value 00591 **/ 00592 00593 uint16_t lm3sEthReadPhyReg(uint8_t address) 00594 { 00595 //Start a read operation 00596 MAC_MCTL_R = (address << 3) | MAC_MCTL_START; 00597 00598 //Wait for the read to complete 00599 while(MAC_MCTL_R & MAC_MCTL_START); 00600 00601 //Return PHY register contents 00602 return MAC_MRXD_R & MAC_MRXD_MDRX_M; 00603 } 00604 00605 00606 /** 00607 * @brief Dump PHY registers for debugging purpose 00608 **/ 00609 00610 void lm3sEthDumpPhyReg(void) 00611 { 00612 uint8_t i; 00613 00614 //Loop through PHY registers 00615 for(i = 0; i < 32; i++) 00616 { 00617 //Display current PHY register 00618 TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, lm3sEthReadPhyReg(i)); 00619 } 00620 00621 //Terminate with a line feed 00622 TRACE_DEBUG("\r\n"); 00623 } 00624
Generated on Tue Jul 12 2022 17:10:14 by
