A web server for monitoring and controlling a MakerBot Replicator over the USB host and ethernet.

Dependencies:   IAP NTPClient RTC mbed-rtos mbed Socket lwip-sys lwip BurstSPI

Fork of LPC1768_Mini-DK by Frank Vannieuwkerke

Makerbot Server for LPC1768 Copyright (c) 2013, jake (at) allaboutjake (dot) com All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • The name of the author and/or copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, AUTHOR, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Warnings:

This is not a commercial product or a hardened and secure network appliance. It is intended as a thought experiment or proof of concept and should not be relied upon in any way. Always operate your 3D printer in a safe and controlled manner.

Do not connect this directly to the exposed internet. It is intended to be behind a secure firewall (and NAT) such that it will only accept commands from the local network. Imagine how much fun a hacker could have instructing your 3D printer to continually print Standford bunnies. Well it could be much worse then that- a malicious user could send commands that could crash your machine (both in the software sense, as well as in the "smash your moving parts against the side of the machine repeatedly sense), overheat your extruders, cause your build plate to catch fire, and do severe damage to the machine, any surrounding building and propery. You have been warned.

Never print unattended and be ready to step in and stop the machine if something goes wrong. Keep in mind, a 3D printer has heaters that are operating at high temperatures, and if something starts to burn, it could cause damage to the machine, other property, and/or hurt yourself, pets, or others.

You should understand what you are doing. The source code here is not intended as a finished product or set of step by step instructions. You should engineer your own solution, which may wind up being better than mine.

Proceed at your own risk. You've been warned. (Several times) If you break your Makerbot, burn your house down, or injure yourself or others, I take no responsibility.

Introduction

I've been working on a side project to solve the "last mile" problem for people wanting to print from the network on their bots. I feel like the first half of the problem is solved with the FlashAir- getting the files to the card. The next step is a lightweight way of sending the "play back capture" command to the bot.

I looked around for a microcontroller platform that supports both networking and can function as a USB host. I happened to have an mbed (mbed) on hand that fit the bill. The mbed also has a working online toolchain (you need to own an mbed to gain access to the compiler). Some people don't like the online development environment, but I'm a fan of "working" and "Mac compatible." It was a good start, but cost wise, you would need an mbed LPC1768 module and some sort of carrier board that has both USB host and ethernet, or rig up your own connector solution. I happened to also have a Seedstudio mbed shield carrier board. This provides ethernet and USB connectors, but is another $25, putting the solution at around $75.

I also had an LPC1768 development board here called the "Mini-DK2". It has a USB host and a wired ethernet connector on board (search ebay if you're interested). It's a single-board solution that costs only $32 (and for $40 you can get one with a touchscreen) Its the cheapest development board I've seen with both USB host and an ethernet connector. I considered RasPi, but I'm not on that bandwagon. Since I had the Mini-DK2 on hand from another project that never went anywhere, I moved from the mbed module and carrier board to the DK2.

The mbed environment can compile binaries that work on the DK2 (again, you need to own at least one 1768 mbed already to get a license to use the compiler), and the mbed libraries provide some nice features. A USB Host library and and Ethernet library were readily available. The USBHost library didn't quite work out of the box. It took some time and more learning about the USB protocols than I would have liked, but I have the board communicating over the USB Host and the Makerbot.

Changes to stock mbed libraries

Many libraries are imported, but then converted to folders as to unlink them.

mbed provides a USHost library that includes a USBHostSerial object for connecting to CDC serial devices. Unfortunately, it did not work for me out of the box. I spent some time learning about USB protocols. One good reference is [Jan Axelson's Lakeview Research](http://www.lvr.com/usb_virtual_com_port.htm) discussion about CDC.

I found that the stock library was sending the control transfers to Interface 1. From what I understand, the control transfers needed to go to interface 0. I modified the USBHostSerial library to correct this, and the serial port interface came to life.

Next, I found that I wasn't able to get reliable communication. I traced it to what I think is an odd C++ inheritance and override problem. The USBHostSerial class implements the Stream interface, allowing printf/scanf operations. This is done by overriding the virtual _getc and _putc methods. Unfortunately, and for a reason I can't understand, these methods were not being called consistently. Sometimes they would work, but other times they would not. My solution was to implement transmit/receive methods with different names, and since the names were different, they seemed to get called consistently. I'd like to learn exactly what's going on here, but I don't feel like debugging it for academic purposes when it works just fine with the added methods.

Usage

Connect up your chosen dev board to power, ethernet and the USB host to the Makerbot's USB cable. The Mini-DK uses a USB-OTG adapter for the USB host. If you're using a Mini-DK board with an LCD, it will inform you of it's IP address on the display. This means it is now listening for a connection on port 7654.

If you are using an mbed dev board, or a Mini-DK without a display, the message will be directed to the serial console. Connect your computer to the appropriate port at a baud rate of 115200 to see the messages.

Use a telnet client to connect to the given IP address at port 7654. Telnet clients typically revert to "line mode" on ports other than 21. This means you get a local echo and the command isn't sent until you press enter.

Once connected, you can send the following commands:

A <username>:<password> : Set a username & password for the web interface and the telnet interface. Use the format shown with a colon separating the username from the password.

V : Print the version and Makerbot name, as well as the local firmware version (the Makerbot_Server firmware as discussed here).

B <filename.x3g> : Build from SD the given filename. According tot he protocol spec, this command is limited to 12 characters, so 8.3 filenames only.

P : Pause an active build

R : Resume active build

C : Cancel build- note that this immediately halts the build and does not clear the build area. You might want to pause the build first, and then cancel shortly after to make sure the nozzle isn't left hot and in contact with a printed part.

S : Print build status, tool and platform temps

Q : Quit and logout

The Mini-DK has two onboard buttons (besides the ISP and reset buttons). Currently one button will trigger a pause (if the Makerbot is printing) and the other will resume (if the Makerbot it paused)

Compiling

Edit "Target.h" to set whether you're building for an MBED module or the Mini-DK2

Installation

If you are using a mbed, then you can simply load the BIN file to the mbed using the mass storage bootloader. The mbed mounts as if it were a USB thumbdrive, and you copy the BIN file to the drive. After a reset, you're running the installed firmware.

The MiniDK has a serial bootloader. You connect to this bootloader from the "top" USB connector (not the USB host one). Hold down the ISP button and then tap the reset button and then release the ISP button to put it into programming mode. I use [lpc21isp](http://sourceforge.net/projects/lpc21isp/) to load the binary. The other option is FlashMagic, which uses HEX files, so you'll need to use some sort of bin2hex utility to convert the firmware file if you use this utility. I can't really say if/how this works, as I don't use this method. See this (http://mbed.org/users/frankvnk/notebook/lpc1768-mini-dk/) for more info.

Credits

Some credits, where credit is due.

EthernetInterface - modified to include PHY code for both the MiniDK2 and MBED based on selected #definitions

Mini-DK - Thanks for Frank and Erik for doing all the heavy lifting getting the MBED compiler and libraries and peripherals working on the Mini-DK2

NTP Client - Thanks to Donatien for this library to set the clock over the network

RTC - Thanks to Erik for the RTC library. I've got it in my project, but I don't think I'm using it for anything (yet).

SimpleSocket - Thanks to Yamaguchi-san. Modified slightly to take out references to EthernetInterface::init() and ::getIPAddress(). For some reason these don't like to be called in a thread.

JPEGCamera - Thanks again to Yamaguchi-san. Modified to output the JPEG binary over a socket rather than to a file descriptor.

USBHost - modified as noted above

IAP - Thanks to Okano-san. Pulled out of the Mini-DK folder so that I could link it back to the base repository at the root level.

Committer:
jakeb
Date:
Fri Aug 23 21:45:08 2013 +0000
Revision:
15:688b3e3958fd
Initial commit of software v0.2;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jakeb 15:688b3e3958fd 1 /**********************************************************************
jakeb 15:688b3e3958fd 2 * $Id$ lpc17_emac.c 2011-11-20
jakeb 15:688b3e3958fd 3 *//**
jakeb 15:688b3e3958fd 4 * @file lpc17_emac.c
jakeb 15:688b3e3958fd 5 * @brief LPC17 ethernet driver for LWIP
jakeb 15:688b3e3958fd 6 * @version 1.0
jakeb 15:688b3e3958fd 7 * @date 20. Nov. 2011
jakeb 15:688b3e3958fd 8 * @author NXP MCU SW Application Team
jakeb 15:688b3e3958fd 9 *
jakeb 15:688b3e3958fd 10 * Copyright(C) 2011, NXP Semiconductor
jakeb 15:688b3e3958fd 11 * All rights reserved.
jakeb 15:688b3e3958fd 12 *
jakeb 15:688b3e3958fd 13 ***********************************************************************
jakeb 15:688b3e3958fd 14 * Software that is described herein is for illustrative purposes only
jakeb 15:688b3e3958fd 15 * which provides customers with programming information regarding the
jakeb 15:688b3e3958fd 16 * products. This software is supplied "AS IS" without any warranties.
jakeb 15:688b3e3958fd 17 * NXP Semiconductors assumes no responsibility or liability for the
jakeb 15:688b3e3958fd 18 * use of the software, conveys no license or title under any patent,
jakeb 15:688b3e3958fd 19 * copyright, or mask work right to the product. NXP Semiconductors
jakeb 15:688b3e3958fd 20 * reserves the right to make changes in the software without
jakeb 15:688b3e3958fd 21 * notification. NXP Semiconductors also make no representation or
jakeb 15:688b3e3958fd 22 * warranty that such application will be suitable for the specified
jakeb 15:688b3e3958fd 23 * use without further testing or modification.
jakeb 15:688b3e3958fd 24 **********************************************************************/
jakeb 15:688b3e3958fd 25
jakeb 15:688b3e3958fd 26 #include "lwip/opt.h"
jakeb 15:688b3e3958fd 27 #include "lwip/sys.h"
jakeb 15:688b3e3958fd 28 #include "lwip/def.h"
jakeb 15:688b3e3958fd 29 #include "lwip/mem.h"
jakeb 15:688b3e3958fd 30 #include "lwip/pbuf.h"
jakeb 15:688b3e3958fd 31 #include "lwip/stats.h"
jakeb 15:688b3e3958fd 32 #include "lwip/snmp.h"
jakeb 15:688b3e3958fd 33 #include "netif/etharp.h"
jakeb 15:688b3e3958fd 34 #include "netif/ppp_oe.h"
jakeb 15:688b3e3958fd 35
jakeb 15:688b3e3958fd 36 #include "lpc17xx_emac.h"
jakeb 15:688b3e3958fd 37 #include "lpc17_emac.h"
jakeb 15:688b3e3958fd 38 #include "lpc_emac_config.h"
jakeb 15:688b3e3958fd 39 #include "lpc_phy.h"
jakeb 15:688b3e3958fd 40 #include "sys_arch.h"
jakeb 15:688b3e3958fd 41
jakeb 15:688b3e3958fd 42 #include "mbed_interface.h"
jakeb 15:688b3e3958fd 43 #include <string.h>
jakeb 15:688b3e3958fd 44
jakeb 15:688b3e3958fd 45 #ifndef LPC_EMAC_RMII
jakeb 15:688b3e3958fd 46 #error LPC_EMAC_RMII is not defined!
jakeb 15:688b3e3958fd 47 #endif
jakeb 15:688b3e3958fd 48
jakeb 15:688b3e3958fd 49 #if LPC_NUM_BUFF_TXDESCS < 2
jakeb 15:688b3e3958fd 50 #error LPC_NUM_BUFF_TXDESCS must be at least 2
jakeb 15:688b3e3958fd 51 #endif
jakeb 15:688b3e3958fd 52
jakeb 15:688b3e3958fd 53 #if LPC_NUM_BUFF_RXDESCS < 3
jakeb 15:688b3e3958fd 54 #error LPC_NUM_BUFF_RXDESCS must be at least 3
jakeb 15:688b3e3958fd 55 #endif
jakeb 15:688b3e3958fd 56
jakeb 15:688b3e3958fd 57 /** @defgroup lwip17xx_emac_DRIVER lpc17 EMAC driver for LWIP
jakeb 15:688b3e3958fd 58 * @ingroup lwip_emac
jakeb 15:688b3e3958fd 59 *
jakeb 15:688b3e3958fd 60 * @{
jakeb 15:688b3e3958fd 61 */
jakeb 15:688b3e3958fd 62
jakeb 15:688b3e3958fd 63 #if NO_SYS == 0
jakeb 15:688b3e3958fd 64 /** \brief Driver transmit and receive thread priorities
jakeb 15:688b3e3958fd 65 *
jakeb 15:688b3e3958fd 66 * Thread priorities for receive thread and TX cleanup thread. Alter
jakeb 15:688b3e3958fd 67 * to prioritize receive or transmit bandwidth. In a heavily loaded
jakeb 15:688b3e3958fd 68 * system or with LEIP_DEBUG enabled, the priorities might be better
jakeb 15:688b3e3958fd 69 * the same. */
jakeb 15:688b3e3958fd 70 #define RX_PRIORITY (osPriorityNormal)
jakeb 15:688b3e3958fd 71 #define TX_PRIORITY (osPriorityNormal)
jakeb 15:688b3e3958fd 72
jakeb 15:688b3e3958fd 73 /** \brief Debug output formatter lock define
jakeb 15:688b3e3958fd 74 *
jakeb 15:688b3e3958fd 75 * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
jakeb 15:688b3e3958fd 76 * define will allow RX debug messages to not interleave with the
jakeb 15:688b3e3958fd 77 * TX messages (so they are actually readable). Not enabling this
jakeb 15:688b3e3958fd 78 * define when the system is under load will cause the output to
jakeb 15:688b3e3958fd 79 * be unreadable. There is a small tradeoff in performance for this
jakeb 15:688b3e3958fd 80 * so use it only for debug. */
jakeb 15:688b3e3958fd 81 //#define LOCK_RX_THREAD
jakeb 15:688b3e3958fd 82
jakeb 15:688b3e3958fd 83 /** \brief Receive group interrupts
jakeb 15:688b3e3958fd 84 */
jakeb 15:688b3e3958fd 85 #define RXINTGROUP (EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_DONE)
jakeb 15:688b3e3958fd 86
jakeb 15:688b3e3958fd 87 /** \brief Transmit group interrupts
jakeb 15:688b3e3958fd 88 */
jakeb 15:688b3e3958fd 89 #define TXINTGROUP (EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR | EMAC_INT_TX_DONE)
jakeb 15:688b3e3958fd 90
jakeb 15:688b3e3958fd 91 #else
jakeb 15:688b3e3958fd 92 #define RXINTGROUP 0
jakeb 15:688b3e3958fd 93 #define TXINTGROUP 0
jakeb 15:688b3e3958fd 94 #endif
jakeb 15:688b3e3958fd 95
jakeb 15:688b3e3958fd 96 /** \brief Structure of a TX/RX descriptor
jakeb 15:688b3e3958fd 97 */
jakeb 15:688b3e3958fd 98 typedef struct
jakeb 15:688b3e3958fd 99 {
jakeb 15:688b3e3958fd 100 volatile u32_t packet; /**< Pointer to buffer */
jakeb 15:688b3e3958fd 101 volatile u32_t control; /**< Control word */
jakeb 15:688b3e3958fd 102 } LPC_TXRX_DESC_T;
jakeb 15:688b3e3958fd 103
jakeb 15:688b3e3958fd 104 /** \brief Structure of a RX status entry
jakeb 15:688b3e3958fd 105 */
jakeb 15:688b3e3958fd 106 typedef struct
jakeb 15:688b3e3958fd 107 {
jakeb 15:688b3e3958fd 108 volatile u32_t statusinfo; /**< RX status word */
jakeb 15:688b3e3958fd 109 volatile u32_t statushashcrc; /**< RX hash CRC */
jakeb 15:688b3e3958fd 110 } LPC_TXRX_STATUS_T;
jakeb 15:688b3e3958fd 111
jakeb 15:688b3e3958fd 112 /* LPC EMAC driver data structure */
jakeb 15:688b3e3958fd 113 struct lpc_enetdata {
jakeb 15:688b3e3958fd 114 /* prxs must be 8 byte aligned! */
jakeb 15:688b3e3958fd 115 LPC_TXRX_STATUS_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */
jakeb 15:688b3e3958fd 116 struct netif *netif; /**< Reference back to LWIP parent netif */
jakeb 15:688b3e3958fd 117 LPC_TXRX_DESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */
jakeb 15:688b3e3958fd 118 LPC_TXRX_STATUS_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */
jakeb 15:688b3e3958fd 119 LPC_TXRX_DESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */
jakeb 15:688b3e3958fd 120 struct pbuf *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */
jakeb 15:688b3e3958fd 121 u32_t rx_fill_desc_index; /**< RX descriptor next available index */
jakeb 15:688b3e3958fd 122 volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
jakeb 15:688b3e3958fd 123 struct pbuf *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */
jakeb 15:688b3e3958fd 124 u32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */
jakeb 15:688b3e3958fd 125 #if NO_SYS == 0
jakeb 15:688b3e3958fd 126 sys_sem_t RxSem; /**< RX receive thread wakeup semaphore */
jakeb 15:688b3e3958fd 127 sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
jakeb 15:688b3e3958fd 128 sys_mutex_t TXLockMutex; /**< TX critical section mutex */
jakeb 15:688b3e3958fd 129 sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
jakeb 15:688b3e3958fd 130 #endif
jakeb 15:688b3e3958fd 131 };
jakeb 15:688b3e3958fd 132
jakeb 15:688b3e3958fd 133 /** \brief LPC EMAC driver work data
jakeb 15:688b3e3958fd 134 */
jakeb 15:688b3e3958fd 135 ALIGNED(8) struct lpc_enetdata lpc_enetdata;
jakeb 15:688b3e3958fd 136
jakeb 15:688b3e3958fd 137 /* Write a value via the MII link (non-blocking) */
jakeb 15:688b3e3958fd 138 void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value)
jakeb 15:688b3e3958fd 139 {
jakeb 15:688b3e3958fd 140 /* Write value at PHY address and register */
jakeb 15:688b3e3958fd 141 LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
jakeb 15:688b3e3958fd 142 LPC_EMAC->MWTD = Value;
jakeb 15:688b3e3958fd 143 }
jakeb 15:688b3e3958fd 144
jakeb 15:688b3e3958fd 145 /* Write a value via the MII link (blocking) */
jakeb 15:688b3e3958fd 146 err_t lpc_mii_write(u32_t PhyReg, u32_t Value)
jakeb 15:688b3e3958fd 147 {
jakeb 15:688b3e3958fd 148 u32_t mst = 250;
jakeb 15:688b3e3958fd 149 err_t sts = ERR_OK;
jakeb 15:688b3e3958fd 150
jakeb 15:688b3e3958fd 151 /* Write value at PHY address and register */
jakeb 15:688b3e3958fd 152 lpc_mii_write_noblock(PhyReg, Value);
jakeb 15:688b3e3958fd 153
jakeb 15:688b3e3958fd 154 /* Wait for unbusy status */
jakeb 15:688b3e3958fd 155 while (mst > 0) {
jakeb 15:688b3e3958fd 156 sts = LPC_EMAC->MIND;
jakeb 15:688b3e3958fd 157 if ((sts & EMAC_MIND_BUSY) == 0)
jakeb 15:688b3e3958fd 158 mst = 0;
jakeb 15:688b3e3958fd 159 else {
jakeb 15:688b3e3958fd 160 mst--;
jakeb 15:688b3e3958fd 161 osDelay(1);
jakeb 15:688b3e3958fd 162 }
jakeb 15:688b3e3958fd 163 }
jakeb 15:688b3e3958fd 164
jakeb 15:688b3e3958fd 165 if (sts != 0)
jakeb 15:688b3e3958fd 166 sts = ERR_TIMEOUT;
jakeb 15:688b3e3958fd 167
jakeb 15:688b3e3958fd 168 return sts;
jakeb 15:688b3e3958fd 169 }
jakeb 15:688b3e3958fd 170
jakeb 15:688b3e3958fd 171 /* Reads current MII link busy status */
jakeb 15:688b3e3958fd 172 u32_t lpc_mii_is_busy(void)
jakeb 15:688b3e3958fd 173 {
jakeb 15:688b3e3958fd 174 return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY);
jakeb 15:688b3e3958fd 175 }
jakeb 15:688b3e3958fd 176
jakeb 15:688b3e3958fd 177 /* Starts a read operation via the MII link (non-blocking) */
jakeb 15:688b3e3958fd 178 u32_t lpc_mii_read_data(void)
jakeb 15:688b3e3958fd 179 {
jakeb 15:688b3e3958fd 180 u32_t data = LPC_EMAC->MRDD;
jakeb 15:688b3e3958fd 181 LPC_EMAC->MCMD = 0;
jakeb 15:688b3e3958fd 182
jakeb 15:688b3e3958fd 183 return data;
jakeb 15:688b3e3958fd 184 }
jakeb 15:688b3e3958fd 185
jakeb 15:688b3e3958fd 186 /* Starts a read operation via the MII link (non-blocking) */
jakeb 15:688b3e3958fd 187 void lpc_mii_read_noblock(u32_t PhyReg)
jakeb 15:688b3e3958fd 188 {
jakeb 15:688b3e3958fd 189 /* Read value at PHY address and register */
jakeb 15:688b3e3958fd 190 LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
jakeb 15:688b3e3958fd 191 LPC_EMAC->MCMD = EMAC_MCMD_READ;
jakeb 15:688b3e3958fd 192 }
jakeb 15:688b3e3958fd 193
jakeb 15:688b3e3958fd 194 /* Read a value via the MII link (blocking) */
jakeb 15:688b3e3958fd 195 err_t lpc_mii_read(u32_t PhyReg, u32_t *data)
jakeb 15:688b3e3958fd 196 {
jakeb 15:688b3e3958fd 197 u32_t mst = 250;
jakeb 15:688b3e3958fd 198 err_t sts = ERR_OK;
jakeb 15:688b3e3958fd 199
jakeb 15:688b3e3958fd 200 /* Read value at PHY address and register */
jakeb 15:688b3e3958fd 201 lpc_mii_read_noblock(PhyReg);
jakeb 15:688b3e3958fd 202
jakeb 15:688b3e3958fd 203 /* Wait for unbusy status */
jakeb 15:688b3e3958fd 204 while (mst > 0) {
jakeb 15:688b3e3958fd 205 sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL;
jakeb 15:688b3e3958fd 206 if ((sts & EMAC_MIND_BUSY) == 0) {
jakeb 15:688b3e3958fd 207 mst = 0;
jakeb 15:688b3e3958fd 208 *data = LPC_EMAC->MRDD;
jakeb 15:688b3e3958fd 209 } else {
jakeb 15:688b3e3958fd 210 mst--;
jakeb 15:688b3e3958fd 211 osDelay(1);
jakeb 15:688b3e3958fd 212 }
jakeb 15:688b3e3958fd 213 }
jakeb 15:688b3e3958fd 214
jakeb 15:688b3e3958fd 215 LPC_EMAC->MCMD = 0;
jakeb 15:688b3e3958fd 216
jakeb 15:688b3e3958fd 217 if (sts != 0)
jakeb 15:688b3e3958fd 218 sts = ERR_TIMEOUT;
jakeb 15:688b3e3958fd 219
jakeb 15:688b3e3958fd 220 return sts;
jakeb 15:688b3e3958fd 221 }
jakeb 15:688b3e3958fd 222
jakeb 15:688b3e3958fd 223 /** \brief Queues a pbuf into the RX descriptor list
jakeb 15:688b3e3958fd 224 *
jakeb 15:688b3e3958fd 225 * \param[in] lpc_enetif Pointer to the drvier data structure
jakeb 15:688b3e3958fd 226 * \param[in] p Pointer to pbuf to queue
jakeb 15:688b3e3958fd 227 */
jakeb 15:688b3e3958fd 228 static void lpc_rxqueue_pbuf(struct lpc_enetdata *lpc_enetif, struct pbuf *p)
jakeb 15:688b3e3958fd 229 {
jakeb 15:688b3e3958fd 230 u32_t idx;
jakeb 15:688b3e3958fd 231
jakeb 15:688b3e3958fd 232 /* Get next free descriptor index */
jakeb 15:688b3e3958fd 233 idx = lpc_enetif->rx_fill_desc_index;
jakeb 15:688b3e3958fd 234
jakeb 15:688b3e3958fd 235 /* Setup descriptor and clear statuses */
jakeb 15:688b3e3958fd 236 lpc_enetif->prxd[idx].control = EMAC_RCTRL_INT | ((u32_t) (p->len - 1));
jakeb 15:688b3e3958fd 237 lpc_enetif->prxd[idx].packet = (u32_t) p->payload;
jakeb 15:688b3e3958fd 238 lpc_enetif->prxs[idx].statusinfo = 0xFFFFFFFF;
jakeb 15:688b3e3958fd 239 lpc_enetif->prxs[idx].statushashcrc = 0xFFFFFFFF;
jakeb 15:688b3e3958fd 240
jakeb 15:688b3e3958fd 241 /* Save pbuf pointer for push to network layer later */
jakeb 15:688b3e3958fd 242 lpc_enetif->rxb[idx] = p;
jakeb 15:688b3e3958fd 243
jakeb 15:688b3e3958fd 244 /* Wrap at end of descriptor list */
jakeb 15:688b3e3958fd 245 idx++;
jakeb 15:688b3e3958fd 246 if (idx >= LPC_NUM_BUFF_RXDESCS)
jakeb 15:688b3e3958fd 247 idx = 0;
jakeb 15:688b3e3958fd 248
jakeb 15:688b3e3958fd 249 /* Queue descriptor(s) */
jakeb 15:688b3e3958fd 250 lpc_enetif->rx_free_descs -= 1;
jakeb 15:688b3e3958fd 251 lpc_enetif->rx_fill_desc_index = idx;
jakeb 15:688b3e3958fd 252 LPC_EMAC->RxConsumeIndex = idx;
jakeb 15:688b3e3958fd 253
jakeb 15:688b3e3958fd 254 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 255 ("lpc_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
jakeb 15:688b3e3958fd 256 lpc_enetif->rx_free_descs));
jakeb 15:688b3e3958fd 257 }
jakeb 15:688b3e3958fd 258
jakeb 15:688b3e3958fd 259 /** \brief Attempt to allocate and requeue a new pbuf for RX
jakeb 15:688b3e3958fd 260 *
jakeb 15:688b3e3958fd 261 * \param[in] netif Pointer to the netif structure
jakeb 15:688b3e3958fd 262 * \returns 1 if a packet was allocated and requeued, otherwise 0
jakeb 15:688b3e3958fd 263 */
jakeb 15:688b3e3958fd 264 s32_t lpc_rx_queue(struct netif *netif)
jakeb 15:688b3e3958fd 265 {
jakeb 15:688b3e3958fd 266 struct lpc_enetdata *lpc_enetif = netif->state;
jakeb 15:688b3e3958fd 267 struct pbuf *p;
jakeb 15:688b3e3958fd 268 s32_t queued = 0;
jakeb 15:688b3e3958fd 269
jakeb 15:688b3e3958fd 270 /* Attempt to requeue as many packets as possible */
jakeb 15:688b3e3958fd 271 while (lpc_enetif->rx_free_descs > 0) {
jakeb 15:688b3e3958fd 272 /* Allocate a pbuf from the pool. We need to allocate at the
jakeb 15:688b3e3958fd 273 maximum size as we don't know the size of the yet to be
jakeb 15:688b3e3958fd 274 received packet. */
jakeb 15:688b3e3958fd 275 p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
jakeb 15:688b3e3958fd 276 if (p == NULL) {
jakeb 15:688b3e3958fd 277 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 278 ("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
jakeb 15:688b3e3958fd 279 lpc_enetif->rx_free_descs));
jakeb 15:688b3e3958fd 280 return queued;
jakeb 15:688b3e3958fd 281 }
jakeb 15:688b3e3958fd 282
jakeb 15:688b3e3958fd 283 /* pbufs allocated from the RAM pool should be non-chained. */
jakeb 15:688b3e3958fd 284 LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)",
jakeb 15:688b3e3958fd 285 pbuf_clen(p) <= 1);
jakeb 15:688b3e3958fd 286
jakeb 15:688b3e3958fd 287 /* Queue packet */
jakeb 15:688b3e3958fd 288 lpc_rxqueue_pbuf(lpc_enetif, p);
jakeb 15:688b3e3958fd 289
jakeb 15:688b3e3958fd 290 /* Update queued count */
jakeb 15:688b3e3958fd 291 queued++;
jakeb 15:688b3e3958fd 292 }
jakeb 15:688b3e3958fd 293
jakeb 15:688b3e3958fd 294 return queued;
jakeb 15:688b3e3958fd 295 }
jakeb 15:688b3e3958fd 296
jakeb 15:688b3e3958fd 297 /** \brief Sets up the RX descriptor ring buffers.
jakeb 15:688b3e3958fd 298 *
jakeb 15:688b3e3958fd 299 * This function sets up the descriptor list used for receive packets.
jakeb 15:688b3e3958fd 300 *
jakeb 15:688b3e3958fd 301 * \param[in] lpc_enetif Pointer to driver data structure
jakeb 15:688b3e3958fd 302 * \returns Always returns ERR_OK
jakeb 15:688b3e3958fd 303 */
jakeb 15:688b3e3958fd 304 static err_t lpc_rx_setup(struct lpc_enetdata *lpc_enetif)
jakeb 15:688b3e3958fd 305 {
jakeb 15:688b3e3958fd 306 /* Setup pointers to RX structures */
jakeb 15:688b3e3958fd 307 LPC_EMAC->RxDescriptor = (u32_t) &lpc_enetif->prxd[0];
jakeb 15:688b3e3958fd 308 LPC_EMAC->RxStatus = (u32_t) &lpc_enetif->prxs[0];
jakeb 15:688b3e3958fd 309 LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1;
jakeb 15:688b3e3958fd 310
jakeb 15:688b3e3958fd 311 lpc_enetif->rx_free_descs = LPC_NUM_BUFF_RXDESCS;
jakeb 15:688b3e3958fd 312 lpc_enetif->rx_fill_desc_index = 0;
jakeb 15:688b3e3958fd 313
jakeb 15:688b3e3958fd 314 /* Build RX buffer and descriptors */
jakeb 15:688b3e3958fd 315 lpc_rx_queue(lpc_enetif->netif);
jakeb 15:688b3e3958fd 316
jakeb 15:688b3e3958fd 317 return ERR_OK;
jakeb 15:688b3e3958fd 318 }
jakeb 15:688b3e3958fd 319
jakeb 15:688b3e3958fd 320 /** \brief Allocates a pbuf and returns the data from the incoming packet.
jakeb 15:688b3e3958fd 321 *
jakeb 15:688b3e3958fd 322 * \param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 323 * \return a pbuf filled with the received packet (including MAC header)
jakeb 15:688b3e3958fd 324 * NULL on memory error
jakeb 15:688b3e3958fd 325 */
jakeb 15:688b3e3958fd 326 static struct pbuf *lpc_low_level_input(struct netif *netif)
jakeb 15:688b3e3958fd 327 {
jakeb 15:688b3e3958fd 328 struct lpc_enetdata *lpc_enetif = netif->state;
jakeb 15:688b3e3958fd 329 struct pbuf *p = NULL;
jakeb 15:688b3e3958fd 330 u32_t idx, length;
jakeb 15:688b3e3958fd 331
jakeb 15:688b3e3958fd 332 #ifdef LOCK_RX_THREAD
jakeb 15:688b3e3958fd 333 #if NO_SYS == 0
jakeb 15:688b3e3958fd 334 /* Get exclusive access */
jakeb 15:688b3e3958fd 335 sys_mutex_lock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 336 #endif
jakeb 15:688b3e3958fd 337 #endif
jakeb 15:688b3e3958fd 338
jakeb 15:688b3e3958fd 339 /* Monitor RX overrun status. This should never happen unless
jakeb 15:688b3e3958fd 340 (possibly) the internal bus is behing held up by something.
jakeb 15:688b3e3958fd 341 Unless your system is running at a very low clock speed or
jakeb 15:688b3e3958fd 342 there are possibilities that the internal buses may be held
jakeb 15:688b3e3958fd 343 up for a long time, this can probably safely be removed. */
jakeb 15:688b3e3958fd 344 if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) {
jakeb 15:688b3e3958fd 345 LINK_STATS_INC(link.err);
jakeb 15:688b3e3958fd 346 LINK_STATS_INC(link.drop);
jakeb 15:688b3e3958fd 347
jakeb 15:688b3e3958fd 348 /* Temporarily disable RX */
jakeb 15:688b3e3958fd 349 LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN;
jakeb 15:688b3e3958fd 350
jakeb 15:688b3e3958fd 351 /* Reset the RX side */
jakeb 15:688b3e3958fd 352 LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX;
jakeb 15:688b3e3958fd 353 LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN;
jakeb 15:688b3e3958fd 354
jakeb 15:688b3e3958fd 355 /* De-allocate all queued RX pbufs */
jakeb 15:688b3e3958fd 356 for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
jakeb 15:688b3e3958fd 357 if (lpc_enetif->rxb[idx] != NULL) {
jakeb 15:688b3e3958fd 358 pbuf_free(lpc_enetif->rxb[idx]);
jakeb 15:688b3e3958fd 359 lpc_enetif->rxb[idx] = NULL;
jakeb 15:688b3e3958fd 360 }
jakeb 15:688b3e3958fd 361 }
jakeb 15:688b3e3958fd 362
jakeb 15:688b3e3958fd 363 /* Start RX side again */
jakeb 15:688b3e3958fd 364 lpc_rx_setup(lpc_enetif);
jakeb 15:688b3e3958fd 365
jakeb 15:688b3e3958fd 366 /* Re-enable RX */
jakeb 15:688b3e3958fd 367 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
jakeb 15:688b3e3958fd 368
jakeb 15:688b3e3958fd 369 #ifdef LOCK_RX_THREAD
jakeb 15:688b3e3958fd 370 #if NO_SYS == 0
jakeb 15:688b3e3958fd 371 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 372 #endif
jakeb 15:688b3e3958fd 373 #endif
jakeb 15:688b3e3958fd 374
jakeb 15:688b3e3958fd 375 return NULL;
jakeb 15:688b3e3958fd 376 }
jakeb 15:688b3e3958fd 377
jakeb 15:688b3e3958fd 378 /* Determine if a frame has been received */
jakeb 15:688b3e3958fd 379 length = 0;
jakeb 15:688b3e3958fd 380 idx = LPC_EMAC->RxConsumeIndex;
jakeb 15:688b3e3958fd 381 if (LPC_EMAC->RxProduceIndex != idx) {
jakeb 15:688b3e3958fd 382 /* Handle errors */
jakeb 15:688b3e3958fd 383 if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
jakeb 15:688b3e3958fd 384 EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) {
jakeb 15:688b3e3958fd 385 #if LINK_STATS
jakeb 15:688b3e3958fd 386 if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
jakeb 15:688b3e3958fd 387 EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR))
jakeb 15:688b3e3958fd 388 LINK_STATS_INC(link.chkerr);
jakeb 15:688b3e3958fd 389 if (lpc_enetif->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR)
jakeb 15:688b3e3958fd 390 LINK_STATS_INC(link.lenerr);
jakeb 15:688b3e3958fd 391 #endif
jakeb 15:688b3e3958fd 392
jakeb 15:688b3e3958fd 393 /* Drop the frame */
jakeb 15:688b3e3958fd 394 LINK_STATS_INC(link.drop);
jakeb 15:688b3e3958fd 395
jakeb 15:688b3e3958fd 396 /* Re-queue the pbuf for receive */
jakeb 15:688b3e3958fd 397 lpc_enetif->rx_free_descs++;
jakeb 15:688b3e3958fd 398 p = lpc_enetif->rxb[idx];
jakeb 15:688b3e3958fd 399 lpc_enetif->rxb[idx] = NULL;
jakeb 15:688b3e3958fd 400 lpc_rxqueue_pbuf(lpc_enetif, p);
jakeb 15:688b3e3958fd 401
jakeb 15:688b3e3958fd 402 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 403 ("lpc_low_level_input: Packet dropped with errors (0x%x)\n",
jakeb 15:688b3e3958fd 404 lpc_enetif->prxs[idx].statusinfo));
jakeb 15:688b3e3958fd 405 } else {
jakeb 15:688b3e3958fd 406 /* A packet is waiting, get length */
jakeb 15:688b3e3958fd 407 length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1;
jakeb 15:688b3e3958fd 408
jakeb 15:688b3e3958fd 409 /* Zero-copy */
jakeb 15:688b3e3958fd 410 p = lpc_enetif->rxb[idx];
jakeb 15:688b3e3958fd 411 p->len = (u16_t) length;
jakeb 15:688b3e3958fd 412
jakeb 15:688b3e3958fd 413 /* Free pbuf from desriptor */
jakeb 15:688b3e3958fd 414 lpc_enetif->rxb[idx] = NULL;
jakeb 15:688b3e3958fd 415 lpc_enetif->rx_free_descs++;
jakeb 15:688b3e3958fd 416
jakeb 15:688b3e3958fd 417 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 418 ("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n",
jakeb 15:688b3e3958fd 419 p, length, idx));
jakeb 15:688b3e3958fd 420
jakeb 15:688b3e3958fd 421 /* Save size */
jakeb 15:688b3e3958fd 422 p->tot_len = (u16_t) length;
jakeb 15:688b3e3958fd 423 LINK_STATS_INC(link.recv);
jakeb 15:688b3e3958fd 424
jakeb 15:688b3e3958fd 425 /* Queue new buffer(s) */
jakeb 15:688b3e3958fd 426 lpc_rx_queue(lpc_enetif->netif);
jakeb 15:688b3e3958fd 427 }
jakeb 15:688b3e3958fd 428 }
jakeb 15:688b3e3958fd 429
jakeb 15:688b3e3958fd 430 #ifdef LOCK_RX_THREAD
jakeb 15:688b3e3958fd 431 #if NO_SYS == 0
jakeb 15:688b3e3958fd 432 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 433 #endif
jakeb 15:688b3e3958fd 434 #endif
jakeb 15:688b3e3958fd 435
jakeb 15:688b3e3958fd 436 return p;
jakeb 15:688b3e3958fd 437 }
jakeb 15:688b3e3958fd 438
jakeb 15:688b3e3958fd 439 /** \brief Attempt to read a packet from the EMAC interface.
jakeb 15:688b3e3958fd 440 *
jakeb 15:688b3e3958fd 441 * \param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 442 */
jakeb 15:688b3e3958fd 443 void lpc_enetif_input(struct netif *netif)
jakeb 15:688b3e3958fd 444 {
jakeb 15:688b3e3958fd 445 struct eth_hdr *ethhdr;
jakeb 15:688b3e3958fd 446 struct pbuf *p;
jakeb 15:688b3e3958fd 447
jakeb 15:688b3e3958fd 448 /* move received packet into a new pbuf */
jakeb 15:688b3e3958fd 449 p = lpc_low_level_input(netif);
jakeb 15:688b3e3958fd 450 if (p == NULL)
jakeb 15:688b3e3958fd 451 return;
jakeb 15:688b3e3958fd 452
jakeb 15:688b3e3958fd 453 /* points to packet payload, which starts with an Ethernet header */
jakeb 15:688b3e3958fd 454 ethhdr = p->payload;
jakeb 15:688b3e3958fd 455
jakeb 15:688b3e3958fd 456 switch (htons(ethhdr->type)) {
jakeb 15:688b3e3958fd 457 case ETHTYPE_IP:
jakeb 15:688b3e3958fd 458 case ETHTYPE_ARP:
jakeb 15:688b3e3958fd 459 #if PPPOE_SUPPORT
jakeb 15:688b3e3958fd 460 case ETHTYPE_PPPOEDISC:
jakeb 15:688b3e3958fd 461 case ETHTYPE_PPPOE:
jakeb 15:688b3e3958fd 462 #endif /* PPPOE_SUPPORT */
jakeb 15:688b3e3958fd 463 /* full packet send to tcpip_thread to process */
jakeb 15:688b3e3958fd 464 if (netif->input(p, netif) != ERR_OK) {
jakeb 15:688b3e3958fd 465 LWIP_DEBUGF(NETIF_DEBUG, ("lpc_enetif_input: IP input error\n"));
jakeb 15:688b3e3958fd 466 /* Free buffer */
jakeb 15:688b3e3958fd 467 pbuf_free(p);
jakeb 15:688b3e3958fd 468 }
jakeb 15:688b3e3958fd 469 break;
jakeb 15:688b3e3958fd 470
jakeb 15:688b3e3958fd 471 default:
jakeb 15:688b3e3958fd 472 /* Return buffer */
jakeb 15:688b3e3958fd 473 pbuf_free(p);
jakeb 15:688b3e3958fd 474 break;
jakeb 15:688b3e3958fd 475 }
jakeb 15:688b3e3958fd 476 }
jakeb 15:688b3e3958fd 477
jakeb 15:688b3e3958fd 478 /** \brief Determine if the passed address is usable for the ethernet
jakeb 15:688b3e3958fd 479 * DMA controller.
jakeb 15:688b3e3958fd 480 *
jakeb 15:688b3e3958fd 481 * \param[in] addr Address of packet to check for DMA safe operation
jakeb 15:688b3e3958fd 482 * \return 1 if the packet address is not safe, otherwise 0
jakeb 15:688b3e3958fd 483 */
jakeb 15:688b3e3958fd 484 static s32_t lpc_packet_addr_notsafe(void *addr) {
jakeb 15:688b3e3958fd 485 /* Check for legal address ranges */
jakeb 15:688b3e3958fd 486 if ((((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20083FFF))) {
jakeb 15:688b3e3958fd 487 return 0;
jakeb 15:688b3e3958fd 488 }
jakeb 15:688b3e3958fd 489 return 1;
jakeb 15:688b3e3958fd 490 }
jakeb 15:688b3e3958fd 491
jakeb 15:688b3e3958fd 492 /** \brief Sets up the TX descriptor ring buffers.
jakeb 15:688b3e3958fd 493 *
jakeb 15:688b3e3958fd 494 * This function sets up the descriptor list used for transmit packets.
jakeb 15:688b3e3958fd 495 *
jakeb 15:688b3e3958fd 496 * \param[in] lpc_enetif Pointer to driver data structure
jakeb 15:688b3e3958fd 497 */
jakeb 15:688b3e3958fd 498 static err_t lpc_tx_setup(struct lpc_enetdata *lpc_enetif)
jakeb 15:688b3e3958fd 499 {
jakeb 15:688b3e3958fd 500 s32_t idx;
jakeb 15:688b3e3958fd 501
jakeb 15:688b3e3958fd 502 /* Build TX descriptors for local buffers */
jakeb 15:688b3e3958fd 503 for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
jakeb 15:688b3e3958fd 504 lpc_enetif->ptxd[idx].control = 0;
jakeb 15:688b3e3958fd 505 lpc_enetif->ptxs[idx].statusinfo = 0xFFFFFFFF;
jakeb 15:688b3e3958fd 506 }
jakeb 15:688b3e3958fd 507
jakeb 15:688b3e3958fd 508 /* Setup pointers to TX structures */
jakeb 15:688b3e3958fd 509 LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetif->ptxd[0];
jakeb 15:688b3e3958fd 510 LPC_EMAC->TxStatus = (u32_t) &lpc_enetif->ptxs[0];
jakeb 15:688b3e3958fd 511 LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1;
jakeb 15:688b3e3958fd 512
jakeb 15:688b3e3958fd 513 lpc_enetif->lpc_last_tx_idx = 0;
jakeb 15:688b3e3958fd 514
jakeb 15:688b3e3958fd 515 return ERR_OK;
jakeb 15:688b3e3958fd 516 }
jakeb 15:688b3e3958fd 517
jakeb 15:688b3e3958fd 518 /** \brief Free TX buffers that are complete
jakeb 15:688b3e3958fd 519 *
jakeb 15:688b3e3958fd 520 * \param[in] lpc_enetif Pointer to driver data structure
jakeb 15:688b3e3958fd 521 * \param[in] cidx EMAC current descriptor comsumer index
jakeb 15:688b3e3958fd 522 */
jakeb 15:688b3e3958fd 523 static void lpc_tx_reclaim_st(struct lpc_enetdata *lpc_enetif, u32_t cidx)
jakeb 15:688b3e3958fd 524 {
jakeb 15:688b3e3958fd 525 #if NO_SYS == 0
jakeb 15:688b3e3958fd 526 /* Get exclusive access */
jakeb 15:688b3e3958fd 527 sys_mutex_lock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 528 #endif
jakeb 15:688b3e3958fd 529
jakeb 15:688b3e3958fd 530 while (cidx != lpc_enetif->lpc_last_tx_idx) {
jakeb 15:688b3e3958fd 531 if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) {
jakeb 15:688b3e3958fd 532 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 533 ("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n",
jakeb 15:688b3e3958fd 534 lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx],
jakeb 15:688b3e3958fd 535 lpc_enetif->lpc_last_tx_idx));
jakeb 15:688b3e3958fd 536 pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]);
jakeb 15:688b3e3958fd 537 lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL;
jakeb 15:688b3e3958fd 538 }
jakeb 15:688b3e3958fd 539
jakeb 15:688b3e3958fd 540 #if NO_SYS == 0
jakeb 15:688b3e3958fd 541 osSemaphoreRelease(lpc_enetif->xTXDCountSem.id);
jakeb 15:688b3e3958fd 542 #endif
jakeb 15:688b3e3958fd 543 lpc_enetif->lpc_last_tx_idx++;
jakeb 15:688b3e3958fd 544 if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS)
jakeb 15:688b3e3958fd 545 lpc_enetif->lpc_last_tx_idx = 0;
jakeb 15:688b3e3958fd 546 }
jakeb 15:688b3e3958fd 547
jakeb 15:688b3e3958fd 548 #if NO_SYS == 0
jakeb 15:688b3e3958fd 549 /* Restore access */
jakeb 15:688b3e3958fd 550 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 551 #endif
jakeb 15:688b3e3958fd 552 }
jakeb 15:688b3e3958fd 553
jakeb 15:688b3e3958fd 554 /** \brief User call for freeingTX buffers that are complete
jakeb 15:688b3e3958fd 555 *
jakeb 15:688b3e3958fd 556 * \param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 557 */
jakeb 15:688b3e3958fd 558 void lpc_tx_reclaim(struct netif *netif)
jakeb 15:688b3e3958fd 559 {
jakeb 15:688b3e3958fd 560 lpc_tx_reclaim_st((struct lpc_enetdata *) netif->state,
jakeb 15:688b3e3958fd 561 LPC_EMAC->TxConsumeIndex);
jakeb 15:688b3e3958fd 562 }
jakeb 15:688b3e3958fd 563
jakeb 15:688b3e3958fd 564 /** \brief Polls if an available TX descriptor is ready. Can be used to
jakeb 15:688b3e3958fd 565 * determine if the low level transmit function will block.
jakeb 15:688b3e3958fd 566 *
jakeb 15:688b3e3958fd 567 * \param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 568 * \return 0 if no descriptors are read, or >0
jakeb 15:688b3e3958fd 569 */
jakeb 15:688b3e3958fd 570 s32_t lpc_tx_ready(struct netif *netif)
jakeb 15:688b3e3958fd 571 {
jakeb 15:688b3e3958fd 572 s32_t fb;
jakeb 15:688b3e3958fd 573 u32_t idx, cidx;
jakeb 15:688b3e3958fd 574
jakeb 15:688b3e3958fd 575 cidx = LPC_EMAC->TxConsumeIndex;
jakeb 15:688b3e3958fd 576 idx = LPC_EMAC->TxProduceIndex;
jakeb 15:688b3e3958fd 577
jakeb 15:688b3e3958fd 578 /* Determine number of free buffers */
jakeb 15:688b3e3958fd 579 if (idx == cidx)
jakeb 15:688b3e3958fd 580 fb = LPC_NUM_BUFF_TXDESCS;
jakeb 15:688b3e3958fd 581 else if (cidx > idx)
jakeb 15:688b3e3958fd 582 fb = (LPC_NUM_BUFF_TXDESCS - 1) -
jakeb 15:688b3e3958fd 583 ((idx + LPC_NUM_BUFF_TXDESCS) - cidx);
jakeb 15:688b3e3958fd 584 else
jakeb 15:688b3e3958fd 585 fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx);
jakeb 15:688b3e3958fd 586
jakeb 15:688b3e3958fd 587 return fb;
jakeb 15:688b3e3958fd 588 }
jakeb 15:688b3e3958fd 589
jakeb 15:688b3e3958fd 590 /** \brief Low level output of a packet. Never call this from an
jakeb 15:688b3e3958fd 591 * interrupt context, as it may block until TX descriptors
jakeb 15:688b3e3958fd 592 * become available.
jakeb 15:688b3e3958fd 593 *
jakeb 15:688b3e3958fd 594 * \param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 595 * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
jakeb 15:688b3e3958fd 596 * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
jakeb 15:688b3e3958fd 597 */
jakeb 15:688b3e3958fd 598 static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
jakeb 15:688b3e3958fd 599 {
jakeb 15:688b3e3958fd 600 struct lpc_enetdata *lpc_enetif = netif->state;
jakeb 15:688b3e3958fd 601 struct pbuf *q;
jakeb 15:688b3e3958fd 602 u8_t *dst;
jakeb 15:688b3e3958fd 603 u32_t idx;
jakeb 15:688b3e3958fd 604 struct pbuf *np;
jakeb 15:688b3e3958fd 605 u32_t dn, notdmasafe = 0;
jakeb 15:688b3e3958fd 606
jakeb 15:688b3e3958fd 607 /* Zero-copy TX buffers may be fragmented across mutliple payload
jakeb 15:688b3e3958fd 608 chains. Determine the number of descriptors needed for the
jakeb 15:688b3e3958fd 609 transfer. The pbuf chaining can be a mess! */
jakeb 15:688b3e3958fd 610 dn = (u32_t) pbuf_clen(p);
jakeb 15:688b3e3958fd 611
jakeb 15:688b3e3958fd 612 /* Test to make sure packet addresses are DMA safe. A DMA safe
jakeb 15:688b3e3958fd 613 address is once that uses external memory or periphheral RAM.
jakeb 15:688b3e3958fd 614 IRAM and FLASH are not safe! */
jakeb 15:688b3e3958fd 615 for (q = p; q != NULL; q = q->next)
jakeb 15:688b3e3958fd 616 notdmasafe += lpc_packet_addr_notsafe(q->payload);
jakeb 15:688b3e3958fd 617
jakeb 15:688b3e3958fd 618 #if LPC_TX_PBUF_BOUNCE_EN==1
jakeb 15:688b3e3958fd 619 /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
jakeb 15:688b3e3958fd 620 created that will be used instead. This requires an copy from the
jakeb 15:688b3e3958fd 621 non-safe DMA region to the new pbuf */
jakeb 15:688b3e3958fd 622 if (notdmasafe) {
jakeb 15:688b3e3958fd 623 /* Allocate a pbuf in DMA memory */
jakeb 15:688b3e3958fd 624 np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
jakeb 15:688b3e3958fd 625 if (np == NULL)
jakeb 15:688b3e3958fd 626 return ERR_MEM;
jakeb 15:688b3e3958fd 627
jakeb 15:688b3e3958fd 628 /* This buffer better be contiguous! */
jakeb 15:688b3e3958fd 629 LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
jakeb 15:688b3e3958fd 630 (pbuf_clen(np) == 1));
jakeb 15:688b3e3958fd 631
jakeb 15:688b3e3958fd 632 /* Copy to DMA safe pbuf */
jakeb 15:688b3e3958fd 633 dst = (u8_t *) np->payload;
jakeb 15:688b3e3958fd 634 for(q = p; q != NULL; q = q->next) {
jakeb 15:688b3e3958fd 635 /* Copy the buffer to the descriptor's buffer */
jakeb 15:688b3e3958fd 636 MEMCPY(dst, (u8_t *) q->payload, q->len);
jakeb 15:688b3e3958fd 637 dst += q->len;
jakeb 15:688b3e3958fd 638 }
jakeb 15:688b3e3958fd 639 np->len = p->tot_len;
jakeb 15:688b3e3958fd 640
jakeb 15:688b3e3958fd 641 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 642 ("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
jakeb 15:688b3e3958fd 643 q, np));
jakeb 15:688b3e3958fd 644
jakeb 15:688b3e3958fd 645 /* use the new buffer for descrptor queueing. The original pbuf will
jakeb 15:688b3e3958fd 646 be de-allocated outsuide this driver. */
jakeb 15:688b3e3958fd 647 p = np;
jakeb 15:688b3e3958fd 648 dn = 1;
jakeb 15:688b3e3958fd 649 }
jakeb 15:688b3e3958fd 650 #else
jakeb 15:688b3e3958fd 651 if (notdmasafe)
jakeb 15:688b3e3958fd 652 LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
jakeb 15:688b3e3958fd 653 (notdmasafe == 0));
jakeb 15:688b3e3958fd 654 #endif
jakeb 15:688b3e3958fd 655
jakeb 15:688b3e3958fd 656 /* Wait until enough descriptors are available for the transfer. */
jakeb 15:688b3e3958fd 657 /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
jakeb 15:688b3e3958fd 658 while (dn > lpc_tx_ready(netif))
jakeb 15:688b3e3958fd 659 #if NO_SYS == 0
jakeb 15:688b3e3958fd 660 osSemaphoreWait(lpc_enetif->xTXDCountSem.id, osWaitForever);
jakeb 15:688b3e3958fd 661 #else
jakeb 15:688b3e3958fd 662 osDelay(1);
jakeb 15:688b3e3958fd 663 #endif
jakeb 15:688b3e3958fd 664
jakeb 15:688b3e3958fd 665 /* Get free TX buffer index */
jakeb 15:688b3e3958fd 666 idx = LPC_EMAC->TxProduceIndex;
jakeb 15:688b3e3958fd 667
jakeb 15:688b3e3958fd 668 #if NO_SYS == 0
jakeb 15:688b3e3958fd 669 /* Get exclusive access */
jakeb 15:688b3e3958fd 670 sys_mutex_lock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 671 #endif
jakeb 15:688b3e3958fd 672
jakeb 15:688b3e3958fd 673 /* Prevent LWIP from de-allocating this pbuf. The driver will
jakeb 15:688b3e3958fd 674 free it once it's been transmitted. */
jakeb 15:688b3e3958fd 675 if (!notdmasafe)
jakeb 15:688b3e3958fd 676 pbuf_ref(p);
jakeb 15:688b3e3958fd 677
jakeb 15:688b3e3958fd 678 /* Setup transfers */
jakeb 15:688b3e3958fd 679 q = p;
jakeb 15:688b3e3958fd 680 while (dn > 0) {
jakeb 15:688b3e3958fd 681 dn--;
jakeb 15:688b3e3958fd 682
jakeb 15:688b3e3958fd 683 /* Only save pointer to free on last descriptor */
jakeb 15:688b3e3958fd 684 if (dn == 0) {
jakeb 15:688b3e3958fd 685 /* Save size of packet and signal it's ready */
jakeb 15:688b3e3958fd 686 lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT |
jakeb 15:688b3e3958fd 687 EMAC_TCTRL_LAST;
jakeb 15:688b3e3958fd 688 lpc_enetif->txb[idx] = p;
jakeb 15:688b3e3958fd 689 }
jakeb 15:688b3e3958fd 690 else {
jakeb 15:688b3e3958fd 691 /* Save size of packet, descriptor is not last */
jakeb 15:688b3e3958fd 692 lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT;
jakeb 15:688b3e3958fd 693 lpc_enetif->txb[idx] = NULL;
jakeb 15:688b3e3958fd 694 }
jakeb 15:688b3e3958fd 695
jakeb 15:688b3e3958fd 696 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
jakeb 15:688b3e3958fd 697 ("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
jakeb 15:688b3e3958fd 698 " size = %d (index=%d)\n", q->payload, dn, q->len, idx));
jakeb 15:688b3e3958fd 699
jakeb 15:688b3e3958fd 700 lpc_enetif->ptxd[idx].packet = (u32_t) q->payload;
jakeb 15:688b3e3958fd 701
jakeb 15:688b3e3958fd 702 q = q->next;
jakeb 15:688b3e3958fd 703
jakeb 15:688b3e3958fd 704 idx++;
jakeb 15:688b3e3958fd 705 if (idx >= LPC_NUM_BUFF_TXDESCS)
jakeb 15:688b3e3958fd 706 idx = 0;
jakeb 15:688b3e3958fd 707 }
jakeb 15:688b3e3958fd 708
jakeb 15:688b3e3958fd 709 LPC_EMAC->TxProduceIndex = idx;
jakeb 15:688b3e3958fd 710
jakeb 15:688b3e3958fd 711 LINK_STATS_INC(link.xmit);
jakeb 15:688b3e3958fd 712
jakeb 15:688b3e3958fd 713 #if NO_SYS == 0
jakeb 15:688b3e3958fd 714 /* Restore access */
jakeb 15:688b3e3958fd 715 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 716 #endif
jakeb 15:688b3e3958fd 717
jakeb 15:688b3e3958fd 718 return ERR_OK;
jakeb 15:688b3e3958fd 719 }
jakeb 15:688b3e3958fd 720
jakeb 15:688b3e3958fd 721 /** \brief LPC EMAC interrupt handler.
jakeb 15:688b3e3958fd 722 *
jakeb 15:688b3e3958fd 723 * This function handles the transmit, receive, and error interrupt of
jakeb 15:688b3e3958fd 724 * the LPC177x_8x. This is meant to be used when NO_SYS=0.
jakeb 15:688b3e3958fd 725 */
jakeb 15:688b3e3958fd 726 void ENET_IRQHandler(void)
jakeb 15:688b3e3958fd 727 {
jakeb 15:688b3e3958fd 728 #if NO_SYS == 1
jakeb 15:688b3e3958fd 729 /* Interrupts are not used without an RTOS */
jakeb 15:688b3e3958fd 730 NVIC_DisableIRQ(ENET_IRQn);
jakeb 15:688b3e3958fd 731 #else
jakeb 15:688b3e3958fd 732 uint32_t ints;
jakeb 15:688b3e3958fd 733
jakeb 15:688b3e3958fd 734 /* Interrupts are of 2 groups - transmit or receive. Based on the
jakeb 15:688b3e3958fd 735 interrupt, kick off the receive or transmit (cleanup) task */
jakeb 15:688b3e3958fd 736
jakeb 15:688b3e3958fd 737 /* Get pending interrupts */
jakeb 15:688b3e3958fd 738 ints = LPC_EMAC->IntStatus;
jakeb 15:688b3e3958fd 739
jakeb 15:688b3e3958fd 740 if (ints & RXINTGROUP) {
jakeb 15:688b3e3958fd 741 /* RX group interrupt(s): Give semaphore to wakeup RX receive task.*/
jakeb 15:688b3e3958fd 742 sys_sem_signal(&lpc_enetdata.RxSem);
jakeb 15:688b3e3958fd 743 }
jakeb 15:688b3e3958fd 744
jakeb 15:688b3e3958fd 745 if (ints & TXINTGROUP) {
jakeb 15:688b3e3958fd 746 /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */
jakeb 15:688b3e3958fd 747 sys_sem_signal(&lpc_enetdata.TxCleanSem);
jakeb 15:688b3e3958fd 748 }
jakeb 15:688b3e3958fd 749
jakeb 15:688b3e3958fd 750 /* Clear pending interrupts */
jakeb 15:688b3e3958fd 751 LPC_EMAC->IntClear = ints;
jakeb 15:688b3e3958fd 752 #endif
jakeb 15:688b3e3958fd 753 }
jakeb 15:688b3e3958fd 754
jakeb 15:688b3e3958fd 755 #if NO_SYS == 0
jakeb 15:688b3e3958fd 756 /** \brief Packet reception task
jakeb 15:688b3e3958fd 757 *
jakeb 15:688b3e3958fd 758 * This task is called when a packet is received. It will
jakeb 15:688b3e3958fd 759 * pass the packet to the LWIP core.
jakeb 15:688b3e3958fd 760 *
jakeb 15:688b3e3958fd 761 * \param[in] pvParameters Not used yet
jakeb 15:688b3e3958fd 762 */
jakeb 15:688b3e3958fd 763 static void packet_rx(void* pvParameters) {
jakeb 15:688b3e3958fd 764 struct lpc_enetdata *lpc_enetif = pvParameters;
jakeb 15:688b3e3958fd 765
jakeb 15:688b3e3958fd 766 while (1) {
jakeb 15:688b3e3958fd 767 /* Wait for receive task to wakeup */
jakeb 15:688b3e3958fd 768 sys_arch_sem_wait(&lpc_enetif->RxSem, 0);
jakeb 15:688b3e3958fd 769
jakeb 15:688b3e3958fd 770 /* Process packets until all empty */
jakeb 15:688b3e3958fd 771 while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex)
jakeb 15:688b3e3958fd 772 lpc_enetif_input(lpc_enetif->netif);
jakeb 15:688b3e3958fd 773 }
jakeb 15:688b3e3958fd 774 }
jakeb 15:688b3e3958fd 775
jakeb 15:688b3e3958fd 776 /** \brief Transmit cleanup task
jakeb 15:688b3e3958fd 777 *
jakeb 15:688b3e3958fd 778 * This task is called when a transmit interrupt occurs and
jakeb 15:688b3e3958fd 779 * reclaims the pbuf and descriptor used for the packet once
jakeb 15:688b3e3958fd 780 * the packet has been transferred.
jakeb 15:688b3e3958fd 781 *
jakeb 15:688b3e3958fd 782 * \param[in] pvParameters Not used yet
jakeb 15:688b3e3958fd 783 */
jakeb 15:688b3e3958fd 784 static void packet_tx(void* pvParameters) {
jakeb 15:688b3e3958fd 785 struct lpc_enetdata *lpc_enetif = pvParameters;
jakeb 15:688b3e3958fd 786 s32_t idx;
jakeb 15:688b3e3958fd 787
jakeb 15:688b3e3958fd 788 while (1) {
jakeb 15:688b3e3958fd 789 /* Wait for transmit cleanup task to wakeup */
jakeb 15:688b3e3958fd 790 sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0);
jakeb 15:688b3e3958fd 791
jakeb 15:688b3e3958fd 792 /* Error handling for TX underruns. This should never happen unless
jakeb 15:688b3e3958fd 793 something is holding the bus or the clocks are going too slow. It
jakeb 15:688b3e3958fd 794 can probably be safely removed. */
jakeb 15:688b3e3958fd 795 if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
jakeb 15:688b3e3958fd 796 LINK_STATS_INC(link.err);
jakeb 15:688b3e3958fd 797 LINK_STATS_INC(link.drop);
jakeb 15:688b3e3958fd 798
jakeb 15:688b3e3958fd 799 #if NO_SYS == 0
jakeb 15:688b3e3958fd 800 /* Get exclusive access */
jakeb 15:688b3e3958fd 801 sys_mutex_lock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 802 #endif
jakeb 15:688b3e3958fd 803 /* Reset the TX side */
jakeb 15:688b3e3958fd 804 LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
jakeb 15:688b3e3958fd 805 LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;
jakeb 15:688b3e3958fd 806
jakeb 15:688b3e3958fd 807 /* De-allocate all queued TX pbufs */
jakeb 15:688b3e3958fd 808 for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
jakeb 15:688b3e3958fd 809 if (lpc_enetif->txb[idx] != NULL) {
jakeb 15:688b3e3958fd 810 pbuf_free(lpc_enetif->txb[idx]);
jakeb 15:688b3e3958fd 811 lpc_enetif->txb[idx] = NULL;
jakeb 15:688b3e3958fd 812 }
jakeb 15:688b3e3958fd 813 }
jakeb 15:688b3e3958fd 814
jakeb 15:688b3e3958fd 815 #if NO_SYS == 0
jakeb 15:688b3e3958fd 816 /* Restore access */
jakeb 15:688b3e3958fd 817 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
jakeb 15:688b3e3958fd 818 #endif
jakeb 15:688b3e3958fd 819 /* Start TX side again */
jakeb 15:688b3e3958fd 820 lpc_tx_setup(lpc_enetif);
jakeb 15:688b3e3958fd 821 } else {
jakeb 15:688b3e3958fd 822 /* Free TX buffers that are done sending */
jakeb 15:688b3e3958fd 823 lpc_tx_reclaim(lpc_enetdata.netif);
jakeb 15:688b3e3958fd 824 }
jakeb 15:688b3e3958fd 825 }
jakeb 15:688b3e3958fd 826 }
jakeb 15:688b3e3958fd 827 #endif
jakeb 15:688b3e3958fd 828
jakeb 15:688b3e3958fd 829 /** \brief Low level init of the MAC and PHY.
jakeb 15:688b3e3958fd 830 *
jakeb 15:688b3e3958fd 831 * \param[in] netif Pointer to LWIP netif structure
jakeb 15:688b3e3958fd 832 */
jakeb 15:688b3e3958fd 833 static err_t low_level_init(struct netif *netif)
jakeb 15:688b3e3958fd 834 {
jakeb 15:688b3e3958fd 835 struct lpc_enetdata *lpc_enetif = netif->state;
jakeb 15:688b3e3958fd 836 err_t err = ERR_OK;
jakeb 15:688b3e3958fd 837
jakeb 15:688b3e3958fd 838 /* Enable MII clocking */
jakeb 15:688b3e3958fd 839 LPC_SC->PCONP |= CLKPWR_PCONP_PCENET;
jakeb 15:688b3e3958fd 840
jakeb 15:688b3e3958fd 841 LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */
jakeb 15:688b3e3958fd 842 LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
jakeb 15:688b3e3958fd 843
jakeb 15:688b3e3958fd 844 /* Reset all MAC logic */
jakeb 15:688b3e3958fd 845 LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX |
jakeb 15:688b3e3958fd 846 EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES |
jakeb 15:688b3e3958fd 847 EMAC_MAC1_SOFT_RES;
jakeb 15:688b3e3958fd 848 LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES |
jakeb 15:688b3e3958fd 849 EMAC_CR_PASS_RUNT_FRM;
jakeb 15:688b3e3958fd 850 osDelay(10);
jakeb 15:688b3e3958fd 851
jakeb 15:688b3e3958fd 852 /* Initial MAC initialization */
jakeb 15:688b3e3958fd 853 LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
jakeb 15:688b3e3958fd 854 LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN |
jakeb 15:688b3e3958fd 855 EMAC_MAC2_VLAN_PAD_EN;
jakeb 15:688b3e3958fd 856 LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
jakeb 15:688b3e3958fd 857
jakeb 15:688b3e3958fd 858 /* Set RMII management clock rate to lowest speed */
jakeb 15:688b3e3958fd 859 LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII;
jakeb 15:688b3e3958fd 860 LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII;
jakeb 15:688b3e3958fd 861
jakeb 15:688b3e3958fd 862 /* Maximum number of retries, 0x37 collision window, gap */
jakeb 15:688b3e3958fd 863 LPC_EMAC->CLRT = EMAC_CLRT_DEF;
jakeb 15:688b3e3958fd 864 LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF;
jakeb 15:688b3e3958fd 865
jakeb 15:688b3e3958fd 866 #if LPC_EMAC_RMII
jakeb 15:688b3e3958fd 867 /* RMII setup */
jakeb 15:688b3e3958fd 868 LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII;
jakeb 15:688b3e3958fd 869 #else
jakeb 15:688b3e3958fd 870 /* MII setup */
jakeb 15:688b3e3958fd 871 LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM;
jakeb 15:688b3e3958fd 872 #endif
jakeb 15:688b3e3958fd 873
jakeb 15:688b3e3958fd 874 /* Initialize the PHY and reset */
jakeb 15:688b3e3958fd 875 err = lpc_phy_init(netif, LPC_EMAC_RMII);
jakeb 15:688b3e3958fd 876 if (err != ERR_OK)
jakeb 15:688b3e3958fd 877 return err;
jakeb 15:688b3e3958fd 878
jakeb 15:688b3e3958fd 879 /* Save station address */
jakeb 15:688b3e3958fd 880 LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] |
jakeb 15:688b3e3958fd 881 (((u32_t) netif->hwaddr[1]) << 8);
jakeb 15:688b3e3958fd 882 LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] |
jakeb 15:688b3e3958fd 883 (((u32_t) netif->hwaddr[3]) << 8);
jakeb 15:688b3e3958fd 884 LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] |
jakeb 15:688b3e3958fd 885 (((u32_t) netif->hwaddr[5]) << 8);
jakeb 15:688b3e3958fd 886
jakeb 15:688b3e3958fd 887 /* Setup transmit and receive descriptors */
jakeb 15:688b3e3958fd 888 if (lpc_tx_setup(lpc_enetif) != ERR_OK)
jakeb 15:688b3e3958fd 889 return ERR_BUF;
jakeb 15:688b3e3958fd 890 if (lpc_rx_setup(lpc_enetif) != ERR_OK)
jakeb 15:688b3e3958fd 891 return ERR_BUF;
jakeb 15:688b3e3958fd 892
jakeb 15:688b3e3958fd 893 /* Enable packet reception */
jakeb 15:688b3e3958fd 894 #if IP_SOF_BROADCAST_RECV
jakeb 15:688b3e3958fd 895 LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN;
jakeb 15:688b3e3958fd 896 #else
jakeb 15:688b3e3958fd 897 LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN;
jakeb 15:688b3e3958fd 898 #endif
jakeb 15:688b3e3958fd 899
jakeb 15:688b3e3958fd 900 /* Clear and enable rx/tx interrupts */
jakeb 15:688b3e3958fd 901 LPC_EMAC->IntClear = 0xFFFF;
jakeb 15:688b3e3958fd 902 LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP;
jakeb 15:688b3e3958fd 903
jakeb 15:688b3e3958fd 904 /* Enable RX and TX */
jakeb 15:688b3e3958fd 905 LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN;
jakeb 15:688b3e3958fd 906 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
jakeb 15:688b3e3958fd 907
jakeb 15:688b3e3958fd 908 return err;
jakeb 15:688b3e3958fd 909 }
jakeb 15:688b3e3958fd 910
jakeb 15:688b3e3958fd 911 /* This function provides a method for the PHY to setup the EMAC
jakeb 15:688b3e3958fd 912 for the PHY negotiated duplex mode */
jakeb 15:688b3e3958fd 913 void lpc_emac_set_duplex(int full_duplex)
jakeb 15:688b3e3958fd 914 {
jakeb 15:688b3e3958fd 915 if (full_duplex) {
jakeb 15:688b3e3958fd 916 LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
jakeb 15:688b3e3958fd 917 LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
jakeb 15:688b3e3958fd 918 LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
jakeb 15:688b3e3958fd 919 } else {
jakeb 15:688b3e3958fd 920 LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP;
jakeb 15:688b3e3958fd 921 LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP;
jakeb 15:688b3e3958fd 922 LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
jakeb 15:688b3e3958fd 923 }
jakeb 15:688b3e3958fd 924 }
jakeb 15:688b3e3958fd 925
jakeb 15:688b3e3958fd 926 /* This function provides a method for the PHY to setup the EMAC
jakeb 15:688b3e3958fd 927 for the PHY negotiated bit rate */
jakeb 15:688b3e3958fd 928 void lpc_emac_set_speed(int mbs_100)
jakeb 15:688b3e3958fd 929 {
jakeb 15:688b3e3958fd 930 if (mbs_100)
jakeb 15:688b3e3958fd 931 LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
jakeb 15:688b3e3958fd 932 else
jakeb 15:688b3e3958fd 933 LPC_EMAC->SUPP = 0;
jakeb 15:688b3e3958fd 934 }
jakeb 15:688b3e3958fd 935
jakeb 15:688b3e3958fd 936 /**
jakeb 15:688b3e3958fd 937 * This function is the ethernet packet send function. It calls
jakeb 15:688b3e3958fd 938 * etharp_output after checking link status.
jakeb 15:688b3e3958fd 939 *
jakeb 15:688b3e3958fd 940 * \param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 941 * \param[in] q Pointer to pbug to send
jakeb 15:688b3e3958fd 942 * \param[in] ipaddr IP address
jakeb 15:688b3e3958fd 943 * \return ERR_OK or error code
jakeb 15:688b3e3958fd 944 */
jakeb 15:688b3e3958fd 945 err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
jakeb 15:688b3e3958fd 946 ip_addr_t *ipaddr)
jakeb 15:688b3e3958fd 947 {
jakeb 15:688b3e3958fd 948 /* Only send packet is link is up */
jakeb 15:688b3e3958fd 949 if (netif->flags & NETIF_FLAG_LINK_UP)
jakeb 15:688b3e3958fd 950 return etharp_output(netif, q, ipaddr);
jakeb 15:688b3e3958fd 951
jakeb 15:688b3e3958fd 952 return ERR_CONN;
jakeb 15:688b3e3958fd 953 }
jakeb 15:688b3e3958fd 954
jakeb 15:688b3e3958fd 955 #if NO_SYS == 0
jakeb 15:688b3e3958fd 956 /* periodic PHY status update */
jakeb 15:688b3e3958fd 957 void phy_update(void const *nif) {
jakeb 15:688b3e3958fd 958 lpc_phy_sts_sm((struct netif*)nif);
jakeb 15:688b3e3958fd 959 }
jakeb 15:688b3e3958fd 960 osTimerDef(phy_update, phy_update);
jakeb 15:688b3e3958fd 961 #endif
jakeb 15:688b3e3958fd 962
jakeb 15:688b3e3958fd 963 /**
jakeb 15:688b3e3958fd 964 * Should be called at the beginning of the program to set up the
jakeb 15:688b3e3958fd 965 * network interface.
jakeb 15:688b3e3958fd 966 *
jakeb 15:688b3e3958fd 967 * This function should be passed as a parameter to netif_add().
jakeb 15:688b3e3958fd 968 *
jakeb 15:688b3e3958fd 969 * @param[in] netif the lwip network interface structure for this lpc_enetif
jakeb 15:688b3e3958fd 970 * @return ERR_OK if the loopif is initialized
jakeb 15:688b3e3958fd 971 * ERR_MEM if private data couldn't be allocated
jakeb 15:688b3e3958fd 972 * any other err_t on error
jakeb 15:688b3e3958fd 973 */
jakeb 15:688b3e3958fd 974 err_t lpc_enetif_init(struct netif *netif)
jakeb 15:688b3e3958fd 975 {
jakeb 15:688b3e3958fd 976 err_t err;
jakeb 15:688b3e3958fd 977
jakeb 15:688b3e3958fd 978 LWIP_ASSERT("netif != NULL", (netif != NULL));
jakeb 15:688b3e3958fd 979
jakeb 15:688b3e3958fd 980 lpc_enetdata.netif = netif;
jakeb 15:688b3e3958fd 981
jakeb 15:688b3e3958fd 982 /* set MAC hardware address */
jakeb 15:688b3e3958fd 983 mbed_mac_address((char *)netif->hwaddr);
jakeb 15:688b3e3958fd 984 netif->hwaddr_len = ETHARP_HWADDR_LEN;
jakeb 15:688b3e3958fd 985
jakeb 15:688b3e3958fd 986 /* maximum transfer unit */
jakeb 15:688b3e3958fd 987 netif->mtu = 1500;
jakeb 15:688b3e3958fd 988
jakeb 15:688b3e3958fd 989 /* device capabilities */
jakeb 15:688b3e3958fd 990 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
jakeb 15:688b3e3958fd 991
jakeb 15:688b3e3958fd 992 /* Initialize the hardware */
jakeb 15:688b3e3958fd 993 netif->state = &lpc_enetdata;
jakeb 15:688b3e3958fd 994 err = low_level_init(netif);
jakeb 15:688b3e3958fd 995 if (err != ERR_OK)
jakeb 15:688b3e3958fd 996 return err;
jakeb 15:688b3e3958fd 997
jakeb 15:688b3e3958fd 998 #if LWIP_NETIF_HOSTNAME
jakeb 15:688b3e3958fd 999 /* Initialize interface hostname */
jakeb 15:688b3e3958fd 1000 netif->hostname = "lwiplpc";
jakeb 15:688b3e3958fd 1001 #endif /* LWIP_NETIF_HOSTNAME */
jakeb 15:688b3e3958fd 1002
jakeb 15:688b3e3958fd 1003 netif->name[0] = 'e';
jakeb 15:688b3e3958fd 1004 netif->name[1] = 'n';
jakeb 15:688b3e3958fd 1005
jakeb 15:688b3e3958fd 1006 netif->output = lpc_etharp_output;
jakeb 15:688b3e3958fd 1007 netif->linkoutput = lpc_low_level_output;
jakeb 15:688b3e3958fd 1008
jakeb 15:688b3e3958fd 1009 /* CMSIS-RTOS, start tasks */
jakeb 15:688b3e3958fd 1010 #if NO_SYS == 0
jakeb 15:688b3e3958fd 1011 #ifdef CMSIS_OS_RTX
jakeb 15:688b3e3958fd 1012 memset(lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data));
jakeb 15:688b3e3958fd 1013 lpc_enetdata.xTXDCountSem.def.semaphore = lpc_enetdata.xTXDCountSem.data;
jakeb 15:688b3e3958fd 1014 #endif
jakeb 15:688b3e3958fd 1015 lpc_enetdata.xTXDCountSem.id = osSemaphoreCreate(&lpc_enetdata.xTXDCountSem.def, LPC_NUM_BUFF_TXDESCS);
jakeb 15:688b3e3958fd 1016 LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL));
jakeb 15:688b3e3958fd 1017
jakeb 15:688b3e3958fd 1018 err = sys_mutex_new(&lpc_enetdata.TXLockMutex);
jakeb 15:688b3e3958fd 1019 LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
jakeb 15:688b3e3958fd 1020
jakeb 15:688b3e3958fd 1021 /* Packet receive task */
jakeb 15:688b3e3958fd 1022 err = sys_sem_new(&lpc_enetdata.RxSem, 0);
jakeb 15:688b3e3958fd 1023 LWIP_ASSERT("RxSem creation error", (err == ERR_OK));
jakeb 15:688b3e3958fd 1024 sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
jakeb 15:688b3e3958fd 1025
jakeb 15:688b3e3958fd 1026 /* Transmit cleanup task */
jakeb 15:688b3e3958fd 1027 err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0);
jakeb 15:688b3e3958fd 1028 LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
jakeb 15:688b3e3958fd 1029 sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
jakeb 15:688b3e3958fd 1030
jakeb 15:688b3e3958fd 1031 /* periodic PHY status update */
jakeb 15:688b3e3958fd 1032 osTimerId phy_timer = osTimerCreate(osTimer(phy_update), osTimerPeriodic, (void *)netif);
jakeb 15:688b3e3958fd 1033 osTimerStart(phy_timer, 250);
jakeb 15:688b3e3958fd 1034 #endif
jakeb 15:688b3e3958fd 1035
jakeb 15:688b3e3958fd 1036 return ERR_OK;
jakeb 15:688b3e3958fd 1037 }
jakeb 15:688b3e3958fd 1038
jakeb 15:688b3e3958fd 1039 /**
jakeb 15:688b3e3958fd 1040 * @}
jakeb 15:688b3e3958fd 1041 */
jakeb 15:688b3e3958fd 1042
jakeb 15:688b3e3958fd 1043 /* --------------------------------- End Of File ------------------------------ */