Webserver+3d print

Dependents:   Nucleo

Revision:
0:8918a71cdbe9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyclone_tcp/drivers/lm3s_eth.c	Sat Feb 04 18:15:49 2017 +0000
@@ -0,0 +1,624 @@
+/**
+ * @file lm3s_eth.c
+ * @brief Luminary Stellaris LM3S Ethernet controller
+ *
+ * @section License
+ *
+ * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
+ *
+ * This file is part of CycloneTCP Open.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * @author Oryx Embedded SARL (www.oryx-embedded.com)
+ * @version 1.7.6
+ **/
+
+//Switch to the appropriate trace level
+#define TRACE_LEVEL NIC_TRACE_LEVEL
+
+//LM3S6965 device?
+#if defined(LM3S6965)
+   #include "lm3s6965.h"
+//LM3S9B92 device?
+#elif defined(LM3S9B92)
+   #include "lm3s9b92.h"
+#endif
+
+//Dependencies
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/sysctl.h"
+#include "core/net.h"
+#include "drivers/lm3s_eth.h"
+#include "debug.h"
+
+//Underlying network interface
+static NetInterface *nicDriverInterface;
+
+//IAR EWARM compiler?
+#if defined(__ICCARM__)
+
+//Transmit buffer
+#pragma data_alignment = 4
+static uint8_t txBuffer[ETH_MAX_FRAME_SIZE + 2];
+//Receive buffer
+#pragma data_alignment = 4
+static uint8_t rxBuffer[ETH_MAX_FRAME_SIZE];
+
+//Keil MDK-ARM or GCC compiler?
+#else
+
+//Transmit buffer
+static uint8_t txBuffer[ETH_MAX_FRAME_SIZE + 2] __attribute__((aligned(4)));
+//Receive buffer
+static uint8_t rxBuffer[ETH_MAX_FRAME_SIZE] __attribute__((aligned(4)));
+
+#endif
+
+
+/**
+ * @brief Stellaris LM3S Ethernet driver
+ **/
+
+const NicDriver lm3sEthDriver =
+{
+   NIC_TYPE_ETHERNET,
+   ETH_MTU,
+   lm3sEthInit,
+   lm3sEthTick,
+   lm3sEthEnableIrq,
+   lm3sEthDisableIrq,
+   lm3sEthEventHandler,
+   lm3sEthSendPacket,
+   lm3sEthSetMulticastFilter,
+   NULL,
+   NULL,
+   NULL,
+   TRUE,
+   TRUE,
+   TRUE,
+   FALSE
+};
+
+
+/**
+ * @brief Stellaris LM3S Ethernet controller initialization
+ * @param[in] interface Underlying network interface
+ * @return Error code
+ **/
+
+error_t lm3sEthInit(NetInterface *interface)
+{
+   uint_t div;
+
+   //Debug message
+   TRACE_INFO("Initializing Stellaris LM3S Ethernet controller...\r\n");
+
+   //Save underlying network interface
+   nicDriverInterface = interface;
+
+   //Enable Ethernet controller clock
+   SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
+   //Reset Ethernet controller
+   SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
+
+   //GPIO configuration
+   lm3sEthInitGpio(interface);
+
+   //The MDC clock frequency cannot exceed 2.5MHz
+   div = SysCtlClockGet() / (2 * 2500000) - 1;
+   //Adjust MDC clock frequency
+   MAC_MDV_R = div & MAC_MDV_DIV_M;
+
+   //Reset PHY transceiver
+   lm3sEthWritePhyReg(PHY_MR0, PHY_MR0_RESET);
+   //Wait for the reset to complete
+   while(lm3sEthReadPhyReg(PHY_MR0) & PHY_MR0_RESET);
+
+   //Dump PHY registers for debugging purpose
+   lm3sEthDumpPhyReg();
+
+   //Configure LED0 and LED1
+   lm3sEthWritePhyReg(PHY_MR23, PHY_MR23_LED0_RXTX | PHY_MR23_LED1_LINK);
+
+   //Set the MAC address
+   MAC_IA0_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
+   MAC_IA1_R = interface->macAddr.w[2];
+
+   //Enable automatic CRC generation and packet padding
+   MAC_TCTL_R = MAC_TCTL_DUPLEX | MAC_TCTL_CRC | MAC_TCTL_PADEN;
+   //Flush the receive FIFO and enable CRC verification
+   MAC_RCTL_R = MAC_RCTL_RSTFIFO | MAC_RCTL_BADCRC;
+
+   //Configure Ethernet interrupts
+   MAC_IM_R = MAC_IM_PHYINTM | MAC_IM_TXEMPM | MAC_IM_RXINTM;
+   //Configure PHY interrupts
+   lm3sEthWritePhyReg(PHY_MR17, PHY_MR17_LSCHG_IE);
+
+   //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
+   IntPriorityGroupingSet(LM3S_ETH_IRQ_PRIORITY_GROUPING);
+   //Configure Ethernet interrupt priority
+   IntPrioritySet(INT_ETH, LM3S_ETH_IRQ_PRIORITY);
+
+   //Enable transmitter
+   MAC_TCTL_R |= MAC_TCTL_TXEN;
+   //Enable receiver
+   MAC_RCTL_R |= MAC_RCTL_RXEN;
+
+   //Accept any packets from the upper layer
+   osSetEvent(&interface->nicTxEvent);
+
+   //Successful initialization
+   return NO_ERROR;
+}
+
+
+//EK-LM3S6965 evaluation board?
+#if defined(USE_EK_LM3S6965)
+
+/**
+ * @brief GPIO configuration
+ * @param[in] interface Underlying network interface
+ **/
+
+void lm3sEthInitGpio(NetInterface *interface)
+{
+   //Enable GPIO clock
+   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
+
+   //Configure status LEDs
+   GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3);
+}
+
+#endif
+
+
+/**
+ * @brief Stellaris LM3S Ethernet timer handler
+ *
+ * This routine is periodically called by the TCP/IP stack to
+ * handle periodic operations such as polling the link state
+ *
+ * @param[in] interface Underlying network interface
+ **/
+
+void lm3sEthTick(NetInterface *interface)
+{
+}
+
+
+/**
+ * @brief Enable interrupts
+ * @param[in] interface Underlying network interface
+ **/
+
+void lm3sEthEnableIrq(NetInterface *interface)
+{
+   //Enable Ethernet interrupts
+   IntEnable(INT_ETH);
+}
+
+
+/**
+ * @brief Disable interrupts
+ * @param[in] interface Underlying network interface
+ **/
+
+void lm3sEthDisableIrq(NetInterface *interface)
+{
+   //Disable Ethernet interrupts
+   IntDisable(INT_ETH);
+}
+
+
+/**
+ * @brief Stellaris LM3S Ethernet interrupt service routine
+ **/
+
+void ETH_IRQHandler(void)
+{
+   bool_t flag;
+   uint32_t status;
+
+   //Enter interrupt service routine
+   osEnterIsr();
+
+   //This flag will be set if a higher priority task must be woken
+   flag = FALSE;
+
+   //Read interrupt status register
+   status = MAC_RIS_R;
+
+   //PHY interrupt?
+   if(status & MAC_RIS_PHYINT)
+   {
+      //Disable PHYINT interrupt
+      MAC_IM_R &= ~MAC_IM_PHYINTM;
+
+      //Set event flag
+      nicDriverInterface->nicEvent = TRUE;
+      //Notify the TCP/IP stack of the event
+      flag |= osSetEventFromIsr(&netEvent);
+   }
+
+   //Transmit FIFO empty?
+   if(status & MAC_RIS_TXEMP)
+   {
+      //Acknowledge TXEMP interrupt
+      MAC_IACK_R = MAC_IACK_TXEMP;
+
+      //Check whether the transmit FIFO is available for writing
+      if(!(MAC_TR_R & MAC_TR_NEWTX))
+      {
+         //Notify the TCP/IP stack that the transmitter is ready to send
+         flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
+      }
+   }
+
+   //Packet received?
+   if(status & MAC_RIS_RXINT)
+   {
+      //Disable RXINT interrupt
+      MAC_IM_R &= ~MAC_IM_RXINTM;
+
+      //Set event flag
+      nicDriverInterface->nicEvent = TRUE;
+      //Notify the TCP/IP stack of the event
+      flag |= osSetEventFromIsr(&netEvent);
+   }
+
+   //Leave interrupt service routine
+   osExitIsr(flag);
+}
+
+
+/**
+ * @brief Stellaris LM3S Ethernet event handler
+ * @param[in] interface Underlying network interface
+ **/
+
+void lm3sEthEventHandler(NetInterface *interface)
+{
+   uint32_t status;
+   uint16_t value;
+
+   //Read interrupt status register
+   status = MAC_RIS_R;
+
+   //PHY interrupt?
+   if(status & MAC_RIS_PHYINT)
+   {
+      //Acknowledge PHYINT interrupt
+      MAC_IACK_R = MAC_IACK_PHYINT;
+      //Read PHY interrupt status register
+      value = lm3sEthReadPhyReg(PHY_MR17);
+
+      //Check whether the link state has changed
+      if(value & PHY_MR17_LSCHG_IE)
+      {
+         //Read PHY status register
+         value = lm3sEthReadPhyReg(PHY_MR1);
+
+         //Check link state
+         if(value & PHY_MR1_LINK)
+         {
+            //Read PHY diagnostic register
+            value = lm3sEthReadPhyReg(PHY_MR18);
+
+            //Get current speed
+            if(value & PHY_MR18_RATE)
+            {
+               //100BASE-TX operation
+               interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
+            }
+            else
+            {
+               //10BASE-T operation
+               interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
+            }
+
+            //Get current duplex mode
+            if(value & PHY_MR18_DPLX)
+            {
+               //Full-Duplex mode
+               interface->duplexMode = NIC_FULL_DUPLEX_MODE;
+               //Update MAC configuration
+               MAC_TCTL_R |= MAC_TCTL_DUPLEX;
+            }
+            else
+            {
+               //Half-Duplex mode
+               interface->duplexMode = NIC_HALF_DUPLEX_MODE;
+               //Update MAC configuration
+               MAC_TCTL_R &= ~MAC_TCTL_DUPLEX;
+            }
+
+            //Update link state
+            interface->linkState = TRUE;
+         }
+         else
+         {
+            //Update link state
+            interface->linkState = FALSE;
+         }
+
+         //Process link state change event
+         nicNotifyLinkChange(interface);
+      }
+   }
+
+   //Packet received?
+   if(status & MAC_RIS_RXINT)
+   {
+      //Acknowledge RXINT interrupt
+      MAC_IACK_R = MAC_IACK_RXINT;
+
+      //Process all the pending packets
+      while(MAC_NP_R & MAC_NP_NPR_M)
+      {
+         //Read incoming packet
+         lm3sEthReceivePacket(interface);
+      }
+   }
+
+   //Re-enable Ethernet interrupts
+   MAC_IM_R = MAC_IM_PHYINTM | MAC_IM_TXEMPM | MAC_IM_RXINTM;
+}
+
+
+/**
+ * @brief Send a packet
+ * @param[in] interface Underlying network interface
+ * @param[in] buffer Multi-part buffer containing the data to send
+ * @param[in] offset Offset to the first data byte
+ * @return Error code
+ **/
+
+error_t lm3sEthSendPacket(NetInterface *interface,
+   const NetBuffer *buffer, size_t offset)
+{
+   size_t i;
+   size_t length;
+   uint32_t *p;
+
+   //Retrieve the length of the packet
+   length = netBufferGetLength(buffer) - offset;
+
+   //Check the frame length
+   if(length < sizeof(EthHeader) || length > ETH_MAX_FRAME_SIZE)
+   {
+      //The transmitter can accept another packet
+      osSetEvent(&interface->nicTxEvent);
+      //Report an error
+      return ERROR_INVALID_LENGTH;
+   }
+
+   //Make sure the transmit FIFO is available for writing
+   if(MAC_TR_R & MAC_TR_NEWTX)
+      return ERROR_FAILURE;
+
+   //Copy user data
+   netBufferRead(txBuffer + 2, buffer, offset, length);
+
+   //The packet is preceded by a 16-bit length field
+   txBuffer[0] = LSB(length - sizeof(EthHeader));
+   txBuffer[1] = MSB(length - sizeof(EthHeader));
+
+   //Point to the beginning of the packet
+   p = (uint32_t *) txBuffer;
+   //Compute the length of the packet in 32-bit words
+   length = (length + 5) / 4;
+
+   //Copy packet to transmit FIFO
+   for(i = 0; i < length; i++)
+      MAC_DATA_R = p[i];
+
+   //Start transmitting
+   MAC_TR_R = MAC_TR_NEWTX;
+
+   //Data successfully written
+   return NO_ERROR;
+}
+
+
+/**
+ * @brief Receive a packet
+ * @return Error code
+ **/
+
+error_t lm3sEthReceivePacket(NetInterface *interface)
+{
+   error_t error;
+   size_t i;
+   size_t n;
+   size_t length;
+   uint32_t data;
+   uint16_t *p;
+
+   //Make sure the FIFO is not empty
+   if(MAC_NP_R & MAC_NP_NPR_M)
+   {
+      //Read the first word
+      data = MAC_DATA_R;
+      //Retrieve the total length of the packet
+      length = data & 0xFFFF;
+
+      //Make sure the length field is valid
+      if(length > 2)
+      {
+         //Point to the beginning of the buffer
+         p = (uint16_t *) rxBuffer;
+
+         //Retrieve the length of the frame
+         length -= 2;
+         //Limit the number of data to be read
+         n = MIN(length, ETH_MAX_FRAME_SIZE);
+
+         //Copy the first half word
+         if(n > 0)
+            *(p++) = (uint16_t) (data >> 16);
+
+         //Copy data from receive FIFO
+         for(i = 2; i < n; i += 4)
+         {
+            //Read a 32-bit word from the FIFO
+            data = MAC_DATA_R;
+            //Write the 32-bit to the receive buffer
+            *(p++) = (uint16_t) data;
+            *(p++) = (uint16_t) (data >> 16);
+         }
+
+         //Skip the remaining bytes
+         while(i < length)
+         {
+            //Read a 32-bit word from the FIFO
+            data = MAC_DATA_R;
+            //Increment byte counter
+            i += 4;
+         }
+
+         //Valid packet received
+         error = NO_ERROR;
+      }
+      else
+      {
+         //Disable receiver
+         MAC_RCTL_R &= ~MAC_RCTL_RXEN;
+         //Flush the receive FIFO
+         MAC_RCTL_R |= MAC_RCTL_RSTFIFO;
+         //Re-enable receiver
+         MAC_RCTL_R |= MAC_RCTL_RXEN;
+
+         //The packet is not valid
+         error = ERROR_INVALID_PACKET;
+      }
+   }
+   else
+   {
+      //No more data in the receive buffer
+      error = ERROR_BUFFER_EMPTY;
+   }
+
+   //Check whether a valid packet has been received
+   if(!error)
+   {
+      //Pass the packet to the upper layer
+      nicProcessPacket(interface, rxBuffer, n);
+   }
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Configure multicast MAC address filtering
+ * @param[in] interface Underlying network interface
+ * @return Error code
+ **/
+
+error_t lm3sEthSetMulticastFilter(NetInterface *interface)
+{
+   uint_t i;
+   bool_t acceptMulticast;
+
+   //This flag will be set if multicast addresses should be accepted
+   acceptMulticast = FALSE;
+
+   //The MAC filter table contains the multicast MAC addresses
+   //to accept when receiving an Ethernet frame
+   for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
+   {
+      //Valid entry?
+      if(interface->macMulticastFilter[i].refCount > 0)
+      {
+         //Accept multicast addresses
+         acceptMulticast = TRUE;
+         //We are done
+         break;
+      }
+   }
+
+   //Enable the reception of multicast frames if necessary
+   if(acceptMulticast)
+      MAC_RCTL_R |= MAC_RCTL_AMUL;
+   else
+      MAC_RCTL_R &= ~MAC_RCTL_AMUL;
+
+   //Successful processing
+   return NO_ERROR;
+}
+
+
+/**
+ * @brief Write PHY register
+ * @param[in] address PHY register address
+ * @param[in] data Register value
+ **/
+
+void lm3sEthWritePhyReg(uint8_t address, uint16_t data)
+{
+   //Data to be written in the PHY register
+   MAC_MTXD_R = data & MAC_MTXD_MDTX_M;
+   //Start a write operation
+   MAC_MCTL_R = (address << 3) | MAC_MCTL_WRITE | MAC_MCTL_START;
+
+   //Wait for the write to complete
+   while(MAC_MCTL_R & MAC_MCTL_START);
+}
+
+
+/**
+ * @brief Read PHY register
+ * @param[in] address PHY register address
+ * @return Register value
+ **/
+
+uint16_t lm3sEthReadPhyReg(uint8_t address)
+{
+   //Start a read operation
+   MAC_MCTL_R = (address << 3) | MAC_MCTL_START;
+
+   //Wait for the read to complete
+   while(MAC_MCTL_R & MAC_MCTL_START);
+
+   //Return PHY register contents
+   return MAC_MRXD_R & MAC_MRXD_MDRX_M;
+}
+
+
+/**
+ * @brief Dump PHY registers for debugging purpose
+ **/
+
+void lm3sEthDumpPhyReg(void)
+{
+   uint8_t i;
+
+   //Loop through PHY registers
+   for(i = 0; i < 32; i++)
+   {
+      //Display current PHY register
+      TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, lm3sEthReadPhyReg(i));
+   }
+
+   //Terminate with a line feed
+   TRACE_DEBUG("\r\n");
+}
+