Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lm3s_eth.c Source File

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