A PicoTCP driver for the lpc1768 mbed board
Dependents: lpc1768-picotcp-demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test TCPSocket_HelloWorld_PicoTCP ... more
pico_dev_mbed_emac.cpp@12:dc845268281a, 2013-07-23 (annotated)
- Committer:
- tass
- Date:
- Tue Jul 23 14:55:25 2013 +0000
- Revision:
- 12:dc845268281a
- Parent:
- 8:0b675bdd074f
- Child:
- 13:d4716335bf83
serial reception goes now through custom made buffered serial port. Improved ping testapp
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tass | 0:b6a2ecc0d29e | 1 | /****************************************************************************** |
tass | 0:b6a2ecc0d29e | 2 | PicoTCP. Copyright (c) 2012-2013 TASS Belgium NV. Some rights reserved. |
tass | 0:b6a2ecc0d29e | 3 | See LICENSE and COPYING for usage. https://github.com/tass-belgium/picotcp |
tass | 0:b6a2ecc0d29e | 4 | |
tass | 0:b6a2ecc0d29e | 5 | This library is free software; you can redistribute it and/or |
tass | 0:b6a2ecc0d29e | 6 | modify it under the terms of the GNU General Public License Version 2 |
tass | 0:b6a2ecc0d29e | 7 | as published by the Free Software Foundation; |
tass | 0:b6a2ecc0d29e | 8 | |
tass | 0:b6a2ecc0d29e | 9 | Some of the code contained in this file is based on mbed.org |
tass | 0:b6a2ecc0d29e | 10 | mbed/libraries/mbed/vendor/NXP/capi/ethernet_api.c module, |
tass | 0:b6a2ecc0d29e | 11 | licensed under the Apache License, Version 2.0 |
tass | 0:b6a2ecc0d29e | 12 | and is Copyright (c) 2006-2013 ARM Limited |
tass | 0:b6a2ecc0d29e | 13 | |
tass | 0:b6a2ecc0d29e | 14 | Authors: Maxime Vincent, Andrei Carp |
tass | 0:b6a2ecc0d29e | 15 | |
tass | 0:b6a2ecc0d29e | 16 | ******************************************************************************/ |
tass | 0:b6a2ecc0d29e | 17 | |
tass | 0:b6a2ecc0d29e | 18 | #include "mbed.h" |
tass | 0:b6a2ecc0d29e | 19 | extern "C" { |
tass | 0:b6a2ecc0d29e | 20 | #include "pico_dev_mbed_emac.h" |
tass | 0:b6a2ecc0d29e | 21 | #include "pico_dev_mbed_emac_private.h" |
tass | 0:b6a2ecc0d29e | 22 | #include "pico_config.h" |
tass | 0:b6a2ecc0d29e | 23 | #include "pico_device.h" |
tass | 0:b6a2ecc0d29e | 24 | #include "pico_stack.h" |
tass | 0:b6a2ecc0d29e | 25 | #include "LPC17xx.h" |
tass | 0:b6a2ecc0d29e | 26 | #include <string.h> |
tass | 0:b6a2ecc0d29e | 27 | } |
daniele | 3:8689b9c62672 | 28 | #include "PicoCondition.h" |
daniele | 4:296b82a1b4b2 | 29 | #include "proxy_endpoint.h" |
tass | 12:dc845268281a | 30 | #include "PicoTerm.h" |
tass | 12:dc845268281a | 31 | |
tass | 12:dc845268281a | 32 | #define emac_dbg ptm_dbg |
daniele | 3:8689b9c62672 | 33 | |
daniele | 5:50ba2a185f35 | 34 | //static PicoCondition rx_condition; |
tass | 0:b6a2ecc0d29e | 35 | |
tass | 0:b6a2ecc0d29e | 36 | /******************************* |
tass | 0:b6a2ecc0d29e | 37 | * Local structs and typedefs * |
tass | 0:b6a2ecc0d29e | 38 | *******************************/ |
tass | 0:b6a2ecc0d29e | 39 | __packed struct RX_DESC_TypeDef { /* RX Descriptor struct */ |
tass | 0:b6a2ecc0d29e | 40 | unsigned int Packet; |
tass | 0:b6a2ecc0d29e | 41 | unsigned int Ctrl; |
tass | 0:b6a2ecc0d29e | 42 | }; |
tass | 0:b6a2ecc0d29e | 43 | typedef struct RX_DESC_TypeDef RX_DESC_TypeDef; |
tass | 0:b6a2ecc0d29e | 44 | |
tass | 0:b6a2ecc0d29e | 45 | __packed struct RX_STAT_TypeDef { /* RX Status struct */ |
tass | 0:b6a2ecc0d29e | 46 | unsigned int Info; |
tass | 0:b6a2ecc0d29e | 47 | unsigned int HashCRC; |
tass | 0:b6a2ecc0d29e | 48 | }; |
tass | 0:b6a2ecc0d29e | 49 | typedef struct RX_STAT_TypeDef RX_STAT_TypeDef; |
tass | 0:b6a2ecc0d29e | 50 | |
tass | 0:b6a2ecc0d29e | 51 | __packed struct TX_DESC_TypeDef { /* TX Descriptor struct */ |
tass | 0:b6a2ecc0d29e | 52 | unsigned int Packet; |
tass | 0:b6a2ecc0d29e | 53 | unsigned int Ctrl; |
tass | 0:b6a2ecc0d29e | 54 | }; |
tass | 0:b6a2ecc0d29e | 55 | typedef struct TX_DESC_TypeDef TX_DESC_TypeDef; |
tass | 0:b6a2ecc0d29e | 56 | |
tass | 0:b6a2ecc0d29e | 57 | __packed struct TX_STAT_TypeDef { /* TX Status struct */ |
tass | 0:b6a2ecc0d29e | 58 | unsigned int Info; |
tass | 0:b6a2ecc0d29e | 59 | }; |
tass | 0:b6a2ecc0d29e | 60 | typedef struct TX_STAT_TypeDef TX_STAT_TypeDef; |
tass | 0:b6a2ecc0d29e | 61 | |
tass | 0:b6a2ecc0d29e | 62 | // To be allocated in the ETH AHB RAM |
tass | 0:b6a2ecc0d29e | 63 | __packed typedef struct emac_dma_data { |
tass | 0:b6a2ecc0d29e | 64 | RX_STAT_TypeDef p_rx_stat[NUM_RX_FRAG]; /**< Pointer to RX statuses */ |
tass | 0:b6a2ecc0d29e | 65 | RX_DESC_TypeDef p_rx_desc[NUM_RX_FRAG]; /**< Pointer to RX descriptor list */ |
tass | 0:b6a2ecc0d29e | 66 | TX_STAT_TypeDef p_tx_stat[NUM_TX_FRAG]; /**< Pointer to TX statuses */ |
tass | 0:b6a2ecc0d29e | 67 | TX_DESC_TypeDef p_tx_desc[NUM_TX_FRAG]; /**< Pointer to TX descriptor list */ |
tass | 0:b6a2ecc0d29e | 68 | uint8_t rx_buf[NUM_RX_FRAG][ETH_MAX_MTU]; /**< RX pbuf pointer list, zero-copy mode */ |
tass | 0:b6a2ecc0d29e | 69 | uint8_t tx_buf[NUM_TX_FRAG][ETH_MAX_MTU]; /**< TX pbuf pointer list, zero-copy mode */ |
tass | 0:b6a2ecc0d29e | 70 | } EMAC_DMA_DATA_T; |
tass | 0:b6a2ecc0d29e | 71 | |
tass | 0:b6a2ecc0d29e | 72 | struct pico_device_mbed_emac { |
tass | 0:b6a2ecc0d29e | 73 | struct pico_device dev; |
tass | 0:b6a2ecc0d29e | 74 | uint16_t mtu; |
tass | 0:b6a2ecc0d29e | 75 | uint8_t mac[PICO_SIZE_ETH]; |
tass | 0:b6a2ecc0d29e | 76 | EMAC_DMA_DATA_T * dma_data; |
tass | 0:b6a2ecc0d29e | 77 | }; |
tass | 0:b6a2ecc0d29e | 78 | |
tass | 0:b6a2ecc0d29e | 79 | /******************** |
tass | 0:b6a2ecc0d29e | 80 | * Global variables * |
tass | 0:b6a2ecc0d29e | 81 | ********************/ |
tass | 0:b6a2ecc0d29e | 82 | |
tass | 0:b6a2ecc0d29e | 83 | /******************* |
tass | 0:b6a2ecc0d29e | 84 | * Local variables * |
tass | 0:b6a2ecc0d29e | 85 | *******************/ |
tass | 0:b6a2ecc0d29e | 86 | static uint16_t *rptr; |
tass | 0:b6a2ecc0d29e | 87 | static uint16_t *tptr; |
tass | 0:b6a2ecc0d29e | 88 | static EMAC_DMA_DATA_T dma_data_ahbsram __attribute__((section("AHBSRAM1"))); |
tass | 0:b6a2ecc0d29e | 89 | |
tass | 0:b6a2ecc0d29e | 90 | DigitalOut led_link(LED2); /* Link */ |
tass | 0:b6a2ecc0d29e | 91 | DigitalOut led_rx(LED3); /* Rx */ |
tass | 0:b6a2ecc0d29e | 92 | DigitalOut led_tx(LED4); /* Tx */ |
tass | 0:b6a2ecc0d29e | 93 | |
tass | 0:b6a2ecc0d29e | 94 | /************************************** |
tass | 0:b6a2ecc0d29e | 95 | * Private helper function prototypes * |
tass | 0:b6a2ecc0d29e | 96 | **************************************/ |
tass | 0:b6a2ecc0d29e | 97 | static void _emac_init(struct pico_device_mbed_emac * mbdev); |
tass | 0:b6a2ecc0d29e | 98 | static void _emac_destroy(struct pico_device *dev); |
tass | 0:b6a2ecc0d29e | 99 | static int _emac_write_PHY (int PhyReg, int Value); |
tass | 0:b6a2ecc0d29e | 100 | static int _emac_read_PHY (unsigned char PhyReg); |
tass | 0:b6a2ecc0d29e | 101 | static void _emac_rx_descr_init (struct pico_device_mbed_emac * mbdev); |
tass | 0:b6a2ecc0d29e | 102 | static void _emac_tx_descr_init (struct pico_device_mbed_emac * mbdev); |
tass | 0:b6a2ecc0d29e | 103 | static int _emac_send_frame(struct pico_device * dev, void * buf, int len); |
tass | 0:b6a2ecc0d29e | 104 | static void _emac_phy_status(void const * dev); |
tass | 0:b6a2ecc0d29e | 105 | static inline unsigned int _emac_clockselect(); |
tass | 0:b6a2ecc0d29e | 106 | static int _pico_emac_poll(struct pico_device *dev, int loop_score); |
tass | 0:b6a2ecc0d29e | 107 | |
daniele | 5:50ba2a185f35 | 108 | struct pico_device *interrupt_mbdev; |
daniele | 5:50ba2a185f35 | 109 | |
tass | 0:b6a2ecc0d29e | 110 | /***************** |
tass | 0:b6a2ecc0d29e | 111 | * CMSIS defines * |
tass | 0:b6a2ecc0d29e | 112 | *****************/ |
tass | 0:b6a2ecc0d29e | 113 | // Timer: For periodic PHY update |
tass | 0:b6a2ecc0d29e | 114 | osTimerDef(_emac_phy_status, _emac_phy_status); |
tass | 0:b6a2ecc0d29e | 115 | |
tass | 0:b6a2ecc0d29e | 116 | /****************************** |
tass | 0:b6a2ecc0d29e | 117 | * Public interface functions * |
tass | 0:b6a2ecc0d29e | 118 | ******************************/ |
tass | 0:b6a2ecc0d29e | 119 | uint32_t intStatus; |
tass | 0:b6a2ecc0d29e | 120 | |
daniele | 4:296b82a1b4b2 | 121 | |
tass | 0:b6a2ecc0d29e | 122 | void ENET_IRQHandler(void) |
tass | 0:b6a2ecc0d29e | 123 | { |
tass | 0:b6a2ecc0d29e | 124 | // Get interrupt flag for enabled interrupts |
tass | 0:b6a2ecc0d29e | 125 | intStatus = (LPC_EMAC->IntStatus & LPC_EMAC->IntEnable); |
tass | 0:b6a2ecc0d29e | 126 | |
tass | 0:b6a2ecc0d29e | 127 | if(intStatus & INT_TX_UNDERRUN) |
tass | 0:b6a2ecc0d29e | 128 | { |
tass | 0:b6a2ecc0d29e | 129 | // this case should be treated |
tass | 12:dc845268281a | 130 | //emac_dbg("TX_UNDERRUN\r\n"); |
tass | 0:b6a2ecc0d29e | 131 | } |
tass | 0:b6a2ecc0d29e | 132 | |
tass | 0:b6a2ecc0d29e | 133 | if(intStatus & INT_RX_OVERRUN) |
tass | 0:b6a2ecc0d29e | 134 | { |
tass | 0:b6a2ecc0d29e | 135 | // this case should be treated |
tass | 12:dc845268281a | 136 | //emac_dbg("INT_RX_OVERRUN\r\n"); |
tass | 0:b6a2ecc0d29e | 137 | } |
tass | 0:b6a2ecc0d29e | 138 | |
tass | 0:b6a2ecc0d29e | 139 | if(intStatus & INT_RX_DONE) |
tass | 0:b6a2ecc0d29e | 140 | { |
daniele | 5:50ba2a185f35 | 141 | picotcp_async_interrupt(interrupt_mbdev); |
daniele | 5:50ba2a185f35 | 142 | //rx_condition.unlock(); |
daniele | 4:296b82a1b4b2 | 143 | |
tass | 0:b6a2ecc0d29e | 144 | } |
tass | 0:b6a2ecc0d29e | 145 | |
tass | 0:b6a2ecc0d29e | 146 | // Clears _ALL_ EMAC interrupt flags |
tass | 0:b6a2ecc0d29e | 147 | LPC_EMAC->IntClear = intStatus; |
tass | 0:b6a2ecc0d29e | 148 | } |
tass | 0:b6a2ecc0d29e | 149 | |
daniele | 3:8689b9c62672 | 150 | static int _emac_poll(struct pico_device_mbed_emac * mbdev); |
daniele | 5:50ba2a185f35 | 151 | /* |
daniele | 3:8689b9c62672 | 152 | void rxThreadCore(void const *arg) |
daniele | 3:8689b9c62672 | 153 | { |
daniele | 3:8689b9c62672 | 154 | struct pico_device_mbed_emac *dev = (struct pico_device_mbed_emac *)arg; |
tass | 12:dc845268281a | 155 | emac_dbg("rx Thread started.\n"); |
daniele | 3:8689b9c62672 | 156 | |
daniele | 3:8689b9c62672 | 157 | while(true) { |
daniele | 3:8689b9c62672 | 158 | rx_condition.lock(); |
daniele | 3:8689b9c62672 | 159 | _emac_poll(dev); |
daniele | 5:50ba2a185f35 | 160 | |
daniele | 3:8689b9c62672 | 161 | } |
daniele | 3:8689b9c62672 | 162 | } |
daniele | 5:50ba2a185f35 | 163 | */ |
daniele | 3:8689b9c62672 | 164 | |
daniele | 3:8689b9c62672 | 165 | |
tass | 0:b6a2ecc0d29e | 166 | |
tass | 0:b6a2ecc0d29e | 167 | struct pico_device *pico_emac_create(char *name) |
tass | 0:b6a2ecc0d29e | 168 | { |
tass | 0:b6a2ecc0d29e | 169 | struct pico_device_mbed_emac *mbdev = (struct pico_device_mbed_emac*) pico_zalloc(sizeof(struct pico_device_mbed_emac)); |
tass | 0:b6a2ecc0d29e | 170 | |
tass | 0:b6a2ecc0d29e | 171 | if (!mbdev) |
tass | 0:b6a2ecc0d29e | 172 | return NULL; |
tass | 0:b6a2ecc0d29e | 173 | |
tass | 0:b6a2ecc0d29e | 174 | // Set pointer to ETH AHB RAM |
tass | 0:b6a2ecc0d29e | 175 | mbdev->dma_data = &dma_data_ahbsram; |
tass | 0:b6a2ecc0d29e | 176 | |
tass | 0:b6a2ecc0d29e | 177 | // Read MAC address from HW |
tass | 0:b6a2ecc0d29e | 178 | mbed_mac_address((char *)mbdev->mac); |
tass | 0:b6a2ecc0d29e | 179 | |
tass | 12:dc845268281a | 180 | //emac_dbg("ETH> Set MAC address to: %x:%x:%x:%x:%x:%x\r\n", mbdev->mac[0], mbdev->mac[1], mbdev->mac[2], mbdev->mac[3], mbdev->mac[4], mbdev->mac[5]); |
tass | 0:b6a2ecc0d29e | 181 | |
tass | 0:b6a2ecc0d29e | 182 | mbdev->mtu = ETH_MAX_MTU; |
tass | 0:b6a2ecc0d29e | 183 | |
tass | 0:b6a2ecc0d29e | 184 | if(0 != pico_device_init((struct pico_device *)mbdev, name, mbdev->mac)) { |
tass | 12:dc845268281a | 185 | //emac_dbg ("ETH> Loop init failed.\n"); |
tass | 0:b6a2ecc0d29e | 186 | _emac_destroy(&mbdev->dev); |
tass | 0:b6a2ecc0d29e | 187 | return NULL; |
tass | 0:b6a2ecc0d29e | 188 | } |
daniele | 1:5704aeb1157d | 189 | |
daniele | 5:50ba2a185f35 | 190 | //pico_queue_protect(((struct pico_device *)mbdev)->q_in); |
tass | 0:b6a2ecc0d29e | 191 | |
tass | 0:b6a2ecc0d29e | 192 | // Set function pointers |
tass | 0:b6a2ecc0d29e | 193 | mbdev->dev.send = _emac_send_frame; |
daniele | 3:8689b9c62672 | 194 | //mbdev->dev.poll = _pico_emac_poll; /* IRQ MODE */ |
daniele | 5:50ba2a185f35 | 195 | mbdev->dev.dsr = _pico_emac_poll; |
tass | 0:b6a2ecc0d29e | 196 | mbdev->dev.destroy = _emac_destroy; |
tass | 0:b6a2ecc0d29e | 197 | |
tass | 0:b6a2ecc0d29e | 198 | // Init EMAC and PHY |
tass | 0:b6a2ecc0d29e | 199 | _emac_init(mbdev); |
tass | 0:b6a2ecc0d29e | 200 | |
tass | 0:b6a2ecc0d29e | 201 | // Create periodic PHY status update thread |
tass | 0:b6a2ecc0d29e | 202 | osTimerId phy_timer = osTimerCreate(osTimer(_emac_phy_status), osTimerPeriodic, (void *)mbdev); |
daniele | 2:a8d9cf10e65a | 203 | osTimerStart(phy_timer, 100); |
daniele | 3:8689b9c62672 | 204 | |
daniele | 5:50ba2a185f35 | 205 | //Thread *rxThread = new Thread(rxThreadCore, (void*)mbdev); |
daniele | 4:296b82a1b4b2 | 206 | |
daniele | 3:8689b9c62672 | 207 | //rxThread->set_priority(osPriorityLow); |
tass | 0:b6a2ecc0d29e | 208 | |
tass | 12:dc845268281a | 209 | //emac_dbg("ETH> Device %s created.\r\n", mbdev->dev.name); |
tass | 0:b6a2ecc0d29e | 210 | |
tass | 0:b6a2ecc0d29e | 211 | return (struct pico_device *)mbdev; |
tass | 0:b6a2ecc0d29e | 212 | } |
tass | 0:b6a2ecc0d29e | 213 | |
tass | 0:b6a2ecc0d29e | 214 | /**************************** |
tass | 0:b6a2ecc0d29e | 215 | * Private helper functions * |
tass | 0:b6a2ecc0d29e | 216 | ****************************/ |
tass | 0:b6a2ecc0d29e | 217 | |
tass | 0:b6a2ecc0d29e | 218 | // Public interface: create/destroy. |
tass | 0:b6a2ecc0d29e | 219 | void _emac_destroy(struct pico_device *dev) |
tass | 0:b6a2ecc0d29e | 220 | { |
tass | 0:b6a2ecc0d29e | 221 | pico_device_destroy(dev); |
tass | 0:b6a2ecc0d29e | 222 | } |
tass | 0:b6a2ecc0d29e | 223 | |
tass | 0:b6a2ecc0d29e | 224 | //extern unsigned int SystemFrequency; |
tass | 0:b6a2ecc0d29e | 225 | static inline unsigned int _emac_clockselect() { |
tass | 0:b6a2ecc0d29e | 226 | if(SystemCoreClock < 10000000) { |
tass | 0:b6a2ecc0d29e | 227 | return 1; |
tass | 0:b6a2ecc0d29e | 228 | } else if(SystemCoreClock < 15000000) { |
tass | 0:b6a2ecc0d29e | 229 | return 2; |
tass | 0:b6a2ecc0d29e | 230 | } else if(SystemCoreClock < 20000000) { |
tass | 0:b6a2ecc0d29e | 231 | return 3; |
tass | 0:b6a2ecc0d29e | 232 | } else if(SystemCoreClock < 25000000) { |
tass | 0:b6a2ecc0d29e | 233 | return 4; |
tass | 0:b6a2ecc0d29e | 234 | } else if(SystemCoreClock < 35000000) { |
tass | 0:b6a2ecc0d29e | 235 | return 5; |
tass | 0:b6a2ecc0d29e | 236 | } else if(SystemCoreClock < 50000000) { |
tass | 0:b6a2ecc0d29e | 237 | return 6; |
tass | 0:b6a2ecc0d29e | 238 | } else if(SystemCoreClock < 70000000) { |
tass | 0:b6a2ecc0d29e | 239 | return 7; |
tass | 0:b6a2ecc0d29e | 240 | } else if(SystemCoreClock < 80000000) { |
tass | 0:b6a2ecc0d29e | 241 | return 8; |
tass | 0:b6a2ecc0d29e | 242 | } else if(SystemCoreClock < 90000000) { |
tass | 0:b6a2ecc0d29e | 243 | return 9; |
tass | 0:b6a2ecc0d29e | 244 | } else if(SystemCoreClock < 100000000) { |
tass | 0:b6a2ecc0d29e | 245 | return 10; |
tass | 0:b6a2ecc0d29e | 246 | } else if(SystemCoreClock < 120000000) { |
tass | 0:b6a2ecc0d29e | 247 | return 11; |
tass | 0:b6a2ecc0d29e | 248 | } else if(SystemCoreClock < 130000000) { |
tass | 0:b6a2ecc0d29e | 249 | return 12; |
tass | 0:b6a2ecc0d29e | 250 | } else if(SystemCoreClock < 140000000) { |
tass | 0:b6a2ecc0d29e | 251 | return 13; |
tass | 0:b6a2ecc0d29e | 252 | } else if(SystemCoreClock < 150000000) { |
tass | 0:b6a2ecc0d29e | 253 | return 15; |
tass | 0:b6a2ecc0d29e | 254 | } else if(SystemCoreClock < 160000000) { |
tass | 0:b6a2ecc0d29e | 255 | return 16; |
tass | 0:b6a2ecc0d29e | 256 | } else { |
tass | 0:b6a2ecc0d29e | 257 | return 0; |
tass | 0:b6a2ecc0d29e | 258 | } |
tass | 0:b6a2ecc0d29e | 259 | } |
tass | 0:b6a2ecc0d29e | 260 | |
tass | 0:b6a2ecc0d29e | 261 | // configure port-pins for use with LAN-controller, |
tass | 0:b6a2ecc0d29e | 262 | // reset it and send the configuration-sequence |
tass | 0:b6a2ecc0d29e | 263 | void _emac_init(struct pico_device_mbed_emac * mbdev) |
tass | 0:b6a2ecc0d29e | 264 | { |
tass | 0:b6a2ecc0d29e | 265 | unsigned int clock = _emac_clockselect(); |
tass | 0:b6a2ecc0d29e | 266 | // the DP83848C PHY clock can be up to 25 Mhz |
tass | 0:b6a2ecc0d29e | 267 | // that means sysclock = 96 Mhz divided by 4 = 24 Mhz |
tass | 0:b6a2ecc0d29e | 268 | // So we *could* set the clock divider to 4 (meaning "clock" = 0) |
tass | 0:b6a2ecc0d29e | 269 | //clock = 0; |
tass | 0:b6a2ecc0d29e | 270 | |
tass | 0:b6a2ecc0d29e | 271 | // Initializes the EMAC ethernet controller |
tass | 0:b6a2ecc0d29e | 272 | unsigned int regv,tout,id1,id2; |
tass | 0:b6a2ecc0d29e | 273 | |
tass | 0:b6a2ecc0d29e | 274 | // Power Up the EMAC controller. |
tass | 0:b6a2ecc0d29e | 275 | LPC_SC->PCONP |= 0x40000000; |
tass | 0:b6a2ecc0d29e | 276 | |
tass | 0:b6a2ecc0d29e | 277 | // on rev. 'A' and later, P1.6 should NOT be set. |
tass | 0:b6a2ecc0d29e | 278 | LPC_PINCON->PINSEL2 = 0x50150105; |
tass | 0:b6a2ecc0d29e | 279 | LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005; |
tass | 0:b6a2ecc0d29e | 280 | |
tass | 0:b6a2ecc0d29e | 281 | // Reset all EMAC internal modules. |
tass | 0:b6a2ecc0d29e | 282 | LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | |
tass | 0:b6a2ecc0d29e | 283 | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES; |
tass | 0:b6a2ecc0d29e | 284 | LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM; |
tass | 0:b6a2ecc0d29e | 285 | |
tass | 0:b6a2ecc0d29e | 286 | // A short delay after reset. |
tass | 0:b6a2ecc0d29e | 287 | for (tout = 100; tout; tout--) __NOP(); // A short delay |
tass | 0:b6a2ecc0d29e | 288 | |
tass | 0:b6a2ecc0d29e | 289 | // Initialize MAC control registers. |
tass | 0:b6a2ecc0d29e | 290 | LPC_EMAC->MAC1 = MAC1_PASS_ALL; |
tass | 0:b6a2ecc0d29e | 291 | LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; |
tass | 0:b6a2ecc0d29e | 292 | // MAC2 = MAC2_CRC_EN | MAC2_PAD_EN | MAC2_VLAN_PAD_EN; |
tass | 0:b6a2ecc0d29e | 293 | |
tass | 0:b6a2ecc0d29e | 294 | LPC_EMAC->MAXF = ETH_MAX_MTU; |
tass | 0:b6a2ecc0d29e | 295 | LPC_EMAC->CLRT = CLRT_DEF; |
tass | 0:b6a2ecc0d29e | 296 | LPC_EMAC->IPGR = IPGR_DEF; |
tass | 0:b6a2ecc0d29e | 297 | |
tass | 0:b6a2ecc0d29e | 298 | // Enable Reduced MII interface. |
tass | 0:b6a2ecc0d29e | 299 | LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM; |
tass | 0:b6a2ecc0d29e | 300 | |
tass | 0:b6a2ecc0d29e | 301 | LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL; // Set clock |
tass | 0:b6a2ecc0d29e | 302 | LPC_EMAC->MCFG |= MCFG_RES_MII; // and reset |
tass | 0:b6a2ecc0d29e | 303 | |
tass | 0:b6a2ecc0d29e | 304 | for(tout = 100; tout; tout--) __NOP(); // A short delay |
tass | 0:b6a2ecc0d29e | 305 | |
tass | 0:b6a2ecc0d29e | 306 | LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL; |
tass | 0:b6a2ecc0d29e | 307 | LPC_EMAC->MCMD = 0; |
tass | 0:b6a2ecc0d29e | 308 | |
tass | 0:b6a2ecc0d29e | 309 | LPC_EMAC->SUPP = SUPP_RES_RMII; // Reset Reduced MII Logic. |
tass | 0:b6a2ecc0d29e | 310 | |
tass | 0:b6a2ecc0d29e | 311 | for (tout = 100; tout; tout--) __NOP(); // A short delay |
tass | 0:b6a2ecc0d29e | 312 | |
tass | 0:b6a2ecc0d29e | 313 | LPC_EMAC->SUPP = 0; |
tass | 0:b6a2ecc0d29e | 314 | |
tass | 0:b6a2ecc0d29e | 315 | // Put the DP83848C in reset mode |
tass | 0:b6a2ecc0d29e | 316 | _emac_write_PHY (PHY_REG_BMCR, 0x8000); |
tass | 0:b6a2ecc0d29e | 317 | |
tass | 0:b6a2ecc0d29e | 318 | // Wait for hardware reset to end. |
tass | 0:b6a2ecc0d29e | 319 | for (tout = 0; tout < 0x100000; tout++) { |
tass | 0:b6a2ecc0d29e | 320 | regv = _emac_read_PHY (PHY_REG_BMCR); |
tass | 0:b6a2ecc0d29e | 321 | if (!(regv & 0x8000)) { |
tass | 0:b6a2ecc0d29e | 322 | // Reset complete |
tass | 0:b6a2ecc0d29e | 323 | break; |
tass | 0:b6a2ecc0d29e | 324 | } |
tass | 0:b6a2ecc0d29e | 325 | } |
tass | 0:b6a2ecc0d29e | 326 | |
tass | 0:b6a2ecc0d29e | 327 | // Check if this is a DP83848C PHY. |
tass | 0:b6a2ecc0d29e | 328 | id1 = _emac_read_PHY (PHY_REG_IDR1); |
tass | 0:b6a2ecc0d29e | 329 | id2 = _emac_read_PHY (PHY_REG_IDR2); |
tass | 0:b6a2ecc0d29e | 330 | if (((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID) { |
tass | 0:b6a2ecc0d29e | 331 | // Configure the PHY device |
tass | 12:dc845268281a | 332 | //emac_dbg("PHY> DP83848C_ID PHY found!\r\n"); |
tass | 0:b6a2ecc0d29e | 333 | // Use autonegotiation about the link speed. |
tass | 0:b6a2ecc0d29e | 334 | _emac_write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG); |
tass | 0:b6a2ecc0d29e | 335 | // Wait to complete Auto_Negotiation. |
tass | 0:b6a2ecc0d29e | 336 | for (tout = 0; tout < 0x100000; tout++) { |
tass | 0:b6a2ecc0d29e | 337 | regv = _emac_read_PHY (PHY_REG_BMSR); |
tass | 0:b6a2ecc0d29e | 338 | if (regv & 0x0020) { |
tass | 0:b6a2ecc0d29e | 339 | // Autonegotiation Complete. |
tass | 0:b6a2ecc0d29e | 340 | break; |
tass | 0:b6a2ecc0d29e | 341 | } |
tass | 0:b6a2ecc0d29e | 342 | } |
tass | 0:b6a2ecc0d29e | 343 | } |
tass | 0:b6a2ecc0d29e | 344 | |
tass | 0:b6a2ecc0d29e | 345 | /* Check the link status. */ |
tass | 0:b6a2ecc0d29e | 346 | for (tout = 0; tout < 0x10000; tout++) { |
tass | 0:b6a2ecc0d29e | 347 | regv = _emac_read_PHY (PHY_REG_STS); |
tass | 0:b6a2ecc0d29e | 348 | if (regv & 0x0001) { |
tass | 0:b6a2ecc0d29e | 349 | // Link is on |
tass | 12:dc845268281a | 350 | //emac_dbg("PHY> Link active!\r\n"); |
tass | 0:b6a2ecc0d29e | 351 | break; |
tass | 0:b6a2ecc0d29e | 352 | } |
tass | 0:b6a2ecc0d29e | 353 | } |
tass | 0:b6a2ecc0d29e | 354 | |
tass | 0:b6a2ecc0d29e | 355 | // Configure Full/Half Duplex mode. |
tass | 0:b6a2ecc0d29e | 356 | if (regv & 0x0004) { |
tass | 0:b6a2ecc0d29e | 357 | // Full duplex is enabled. |
tass | 0:b6a2ecc0d29e | 358 | LPC_EMAC->MAC2 |= MAC2_FULL_DUP; |
tass | 0:b6a2ecc0d29e | 359 | LPC_EMAC->Command |= CR_FULL_DUP; |
tass | 0:b6a2ecc0d29e | 360 | LPC_EMAC->IPGT = IPGT_FULL_DUP; |
tass | 0:b6a2ecc0d29e | 361 | } |
tass | 0:b6a2ecc0d29e | 362 | else { |
tass | 0:b6a2ecc0d29e | 363 | // Half duplex mode. |
tass | 0:b6a2ecc0d29e | 364 | LPC_EMAC->IPGT = IPGT_HALF_DUP; |
tass | 0:b6a2ecc0d29e | 365 | } |
tass | 0:b6a2ecc0d29e | 366 | |
tass | 0:b6a2ecc0d29e | 367 | // Configure 100MBit/10MBit mode |
tass | 0:b6a2ecc0d29e | 368 | if (regv & 0x0002) { |
tass | 0:b6a2ecc0d29e | 369 | // 10MBit mode |
tass | 0:b6a2ecc0d29e | 370 | LPC_EMAC->SUPP = 0; |
tass | 0:b6a2ecc0d29e | 371 | } |
tass | 0:b6a2ecc0d29e | 372 | else { |
tass | 0:b6a2ecc0d29e | 373 | // 100MBit mode |
tass | 0:b6a2ecc0d29e | 374 | LPC_EMAC->SUPP = SUPP_SPEED; |
tass | 0:b6a2ecc0d29e | 375 | } |
tass | 0:b6a2ecc0d29e | 376 | |
tass | 0:b6a2ecc0d29e | 377 | // Set the Ethernet MAC Address registers |
tass | 0:b6a2ecc0d29e | 378 | LPC_EMAC->SA0 = (mbdev->mac[0] << 8) | mbdev->mac[1]; |
tass | 7:608779751f85 | 379 | LPC_EMAC->SA1 = (mbdev->mac[2] << 8) | mbdev->mac[3]; |
tass | 0:b6a2ecc0d29e | 380 | LPC_EMAC->SA2 = (mbdev->mac[4] << 8) | mbdev->mac[5]; |
tass | 0:b6a2ecc0d29e | 381 | |
tass | 0:b6a2ecc0d29e | 382 | // Initialize Tx and Rx DMA Descriptors |
tass | 0:b6a2ecc0d29e | 383 | _emac_rx_descr_init(mbdev); |
tass | 0:b6a2ecc0d29e | 384 | _emac_tx_descr_init(mbdev); |
tass | 0:b6a2ecc0d29e | 385 | |
tass | 0:b6a2ecc0d29e | 386 | // Receive Unicast, Broadcast and Perfect Match Packets |
tass | 0:b6a2ecc0d29e | 387 | LPC_EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN; |
tass | 0:b6a2ecc0d29e | 388 | |
tass | 0:b6a2ecc0d29e | 389 | // Enable receive and transmit mode of MAC Ethernet core |
tass | 0:b6a2ecc0d29e | 390 | LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN); |
tass | 0:b6a2ecc0d29e | 391 | LPC_EMAC->MAC1 |= MAC1_REC_EN; |
tass | 0:b6a2ecc0d29e | 392 | |
tass | 0:b6a2ecc0d29e | 393 | // Enable EMAC interrupts. |
tass | 0:b6a2ecc0d29e | 394 | LPC_EMAC->IntEnable = INT_RX_DONE | INT_RX_OVERRUN | INT_TX_DONE | INT_TX_FIN | INT_TX_ERR | INT_TX_UNDERRUN; |
tass | 0:b6a2ecc0d29e | 395 | |
tass | 0:b6a2ecc0d29e | 396 | // Reset all interrupts |
tass | 0:b6a2ecc0d29e | 397 | LPC_EMAC->IntClear = 0xFFFF; |
tass | 0:b6a2ecc0d29e | 398 | |
tass | 0:b6a2ecc0d29e | 399 | NVIC_SetPriority(ENET_IRQn, EMAC_INTERRUPT_PRIORITY); |
tass | 0:b6a2ecc0d29e | 400 | |
tass | 0:b6a2ecc0d29e | 401 | // Enable the interrupt. |
tass | 0:b6a2ecc0d29e | 402 | NVIC_EnableIRQ(ENET_IRQn); |
daniele | 5:50ba2a185f35 | 403 | // Associate the interrupt to this device |
daniele | 5:50ba2a185f35 | 404 | interrupt_mbdev = (struct pico_device *)mbdev; |
tass | 0:b6a2ecc0d29e | 405 | |
tass | 0:b6a2ecc0d29e | 406 | } |
tass | 0:b6a2ecc0d29e | 407 | |
tass | 0:b6a2ecc0d29e | 408 | |
tass | 0:b6a2ecc0d29e | 409 | static int _emac_write_PHY (int PhyReg, int Value) |
tass | 0:b6a2ecc0d29e | 410 | { |
tass | 0:b6a2ecc0d29e | 411 | unsigned int timeOut; |
tass | 0:b6a2ecc0d29e | 412 | |
tass | 0:b6a2ecc0d29e | 413 | LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg; |
tass | 0:b6a2ecc0d29e | 414 | LPC_EMAC->MWTD = Value; |
tass | 0:b6a2ecc0d29e | 415 | |
tass | 0:b6a2ecc0d29e | 416 | // Wait until operation completed |
tass | 0:b6a2ecc0d29e | 417 | for (timeOut = 0; timeOut < MII_WR_TOUT; timeOut++) { |
tass | 0:b6a2ecc0d29e | 418 | if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { |
tass | 0:b6a2ecc0d29e | 419 | return 0; |
tass | 0:b6a2ecc0d29e | 420 | } |
tass | 0:b6a2ecc0d29e | 421 | } |
tass | 0:b6a2ecc0d29e | 422 | return -1; |
tass | 0:b6a2ecc0d29e | 423 | } |
tass | 0:b6a2ecc0d29e | 424 | |
tass | 0:b6a2ecc0d29e | 425 | static int _emac_read_PHY (unsigned char PhyReg) |
tass | 0:b6a2ecc0d29e | 426 | { |
tass | 0:b6a2ecc0d29e | 427 | unsigned int timeOut; |
tass | 0:b6a2ecc0d29e | 428 | |
tass | 0:b6a2ecc0d29e | 429 | LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg; |
tass | 0:b6a2ecc0d29e | 430 | LPC_EMAC->MCMD = MCMD_READ; |
tass | 0:b6a2ecc0d29e | 431 | |
tass | 0:b6a2ecc0d29e | 432 | for(timeOut = 0; timeOut < MII_RD_TOUT; timeOut++) { // Wait until operation completed |
tass | 0:b6a2ecc0d29e | 433 | if((LPC_EMAC->MIND & MIND_BUSY) == 0) { |
tass | 0:b6a2ecc0d29e | 434 | LPC_EMAC->MCMD = 0; |
tass | 0:b6a2ecc0d29e | 435 | return LPC_EMAC->MRDD; // Return a 16-bit value. |
tass | 0:b6a2ecc0d29e | 436 | } |
tass | 0:b6a2ecc0d29e | 437 | } |
tass | 0:b6a2ecc0d29e | 438 | |
tass | 0:b6a2ecc0d29e | 439 | return -1; |
tass | 0:b6a2ecc0d29e | 440 | } |
tass | 0:b6a2ecc0d29e | 441 | |
tass | 0:b6a2ecc0d29e | 442 | |
tass | 0:b6a2ecc0d29e | 443 | void rx_descr_init (void) |
tass | 0:b6a2ecc0d29e | 444 | { |
tass | 0:b6a2ecc0d29e | 445 | unsigned int i; |
tass | 0:b6a2ecc0d29e | 446 | |
tass | 0:b6a2ecc0d29e | 447 | for (i = 0; i < NUM_RX_FRAG; i++) { |
tass | 0:b6a2ecc0d29e | 448 | RX_DESC_PACKET(i) = RX_BUF(i); |
tass | 0:b6a2ecc0d29e | 449 | RX_DESC_CTRL(i) = RCTRL_INT | (ETH_MAX_MTU-1); |
tass | 0:b6a2ecc0d29e | 450 | RX_STAT_INFO(i) = 0; |
tass | 0:b6a2ecc0d29e | 451 | RX_STAT_HASHCRC(i) = 0; |
tass | 0:b6a2ecc0d29e | 452 | } |
tass | 0:b6a2ecc0d29e | 453 | |
tass | 0:b6a2ecc0d29e | 454 | // Set EMAC Receive Descriptor Registers. |
tass | 0:b6a2ecc0d29e | 455 | LPC_EMAC->RxDescriptor = RX_DESC_BASE; |
tass | 0:b6a2ecc0d29e | 456 | LPC_EMAC->RxStatus = RX_STAT_BASE; |
tass | 0:b6a2ecc0d29e | 457 | LPC_EMAC->RxDescriptorNumber= NUM_RX_FRAG-1; |
tass | 0:b6a2ecc0d29e | 458 | |
tass | 0:b6a2ecc0d29e | 459 | // Rx Descriptors Point to 0 |
tass | 0:b6a2ecc0d29e | 460 | LPC_EMAC->RxConsumeIndex = 0; |
tass | 0:b6a2ecc0d29e | 461 | } |
tass | 0:b6a2ecc0d29e | 462 | |
tass | 0:b6a2ecc0d29e | 463 | |
tass | 0:b6a2ecc0d29e | 464 | void tx_descr_init (void) { |
tass | 0:b6a2ecc0d29e | 465 | unsigned int i; |
tass | 0:b6a2ecc0d29e | 466 | |
tass | 0:b6a2ecc0d29e | 467 | for (i = 0; i < NUM_TX_FRAG; i++) { |
tass | 0:b6a2ecc0d29e | 468 | TX_DESC_PACKET(i) = TX_BUF(i); |
tass | 0:b6a2ecc0d29e | 469 | TX_DESC_CTRL(i) = 0; |
tass | 0:b6a2ecc0d29e | 470 | TX_STAT_INFO(i) = 0; |
tass | 0:b6a2ecc0d29e | 471 | } |
tass | 0:b6a2ecc0d29e | 472 | |
tass | 0:b6a2ecc0d29e | 473 | // Set EMAC Transmit Descriptor Registers. |
tass | 0:b6a2ecc0d29e | 474 | LPC_EMAC->TxDescriptor = TX_DESC_BASE; |
tass | 0:b6a2ecc0d29e | 475 | LPC_EMAC->TxStatus = TX_STAT_BASE; |
tass | 0:b6a2ecc0d29e | 476 | LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; |
tass | 0:b6a2ecc0d29e | 477 | |
tass | 0:b6a2ecc0d29e | 478 | // Tx Descriptors Point to 0 |
tass | 0:b6a2ecc0d29e | 479 | LPC_EMAC->TxProduceIndex = 0; |
tass | 0:b6a2ecc0d29e | 480 | } |
tass | 0:b6a2ecc0d29e | 481 | |
tass | 0:b6a2ecc0d29e | 482 | |
tass | 0:b6a2ecc0d29e | 483 | static void _emac_rx_descr_init (struct pico_device_mbed_emac * mbdev) |
tass | 0:b6a2ecc0d29e | 484 | { |
tass | 0:b6a2ecc0d29e | 485 | unsigned int i; |
tass | 0:b6a2ecc0d29e | 486 | |
tass | 0:b6a2ecc0d29e | 487 | for (i = 0; i < NUM_RX_FRAG; i++) { |
tass | 0:b6a2ecc0d29e | 488 | // Fill in pointers to ETH DMA AHB RAM |
tass | 0:b6a2ecc0d29e | 489 | mbdev->dma_data->p_rx_desc[i].Packet = (uint32_t)&(mbdev->dma_data->rx_buf[i][0]); |
tass | 0:b6a2ecc0d29e | 490 | mbdev->dma_data->p_rx_desc[i].Ctrl = RCTRL_INT | (ETH_MAX_MTU-1); |
tass | 0:b6a2ecc0d29e | 491 | mbdev->dma_data->p_rx_stat[i].Info = 0; |
tass | 0:b6a2ecc0d29e | 492 | mbdev->dma_data->p_rx_stat[i].HashCRC = 0; |
tass | 0:b6a2ecc0d29e | 493 | } |
tass | 0:b6a2ecc0d29e | 494 | |
tass | 0:b6a2ecc0d29e | 495 | // Set EMAC Receive Descriptor Registers. |
tass | 0:b6a2ecc0d29e | 496 | LPC_EMAC->RxDescriptor = (uint32_t)&(mbdev->dma_data->p_rx_desc[0]); |
tass | 0:b6a2ecc0d29e | 497 | LPC_EMAC->RxStatus = (uint32_t)&(mbdev->dma_data->p_rx_stat[0]); |
tass | 0:b6a2ecc0d29e | 498 | LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1; |
tass | 0:b6a2ecc0d29e | 499 | |
tass | 0:b6a2ecc0d29e | 500 | // Rx Descriptors Point to 0 |
tass | 0:b6a2ecc0d29e | 501 | LPC_EMAC->RxConsumeIndex = 0; |
tass | 0:b6a2ecc0d29e | 502 | } |
tass | 0:b6a2ecc0d29e | 503 | |
tass | 0:b6a2ecc0d29e | 504 | static void _emac_tx_descr_init (struct pico_device_mbed_emac * mbdev) { |
tass | 0:b6a2ecc0d29e | 505 | unsigned int i; |
tass | 0:b6a2ecc0d29e | 506 | |
tass | 0:b6a2ecc0d29e | 507 | for (i = 0; i < NUM_TX_FRAG; i++) { |
tass | 0:b6a2ecc0d29e | 508 | mbdev->dma_data->p_tx_desc[i].Packet = (uint32_t)&(mbdev->dma_data->tx_buf[i][0]); |
tass | 0:b6a2ecc0d29e | 509 | mbdev->dma_data->p_tx_desc[i].Ctrl = 0; |
tass | 0:b6a2ecc0d29e | 510 | mbdev->dma_data->p_tx_stat[i].Info = 0; |
tass | 0:b6a2ecc0d29e | 511 | } |
tass | 0:b6a2ecc0d29e | 512 | |
tass | 0:b6a2ecc0d29e | 513 | // Set EMAC Transmit Descriptor Registers. |
tass | 0:b6a2ecc0d29e | 514 | LPC_EMAC->TxDescriptor = (uint32_t)&(mbdev->dma_data->p_tx_desc[0]); |
tass | 0:b6a2ecc0d29e | 515 | LPC_EMAC->TxStatus = (uint32_t)&(mbdev->dma_data->p_tx_stat[0]); |
tass | 0:b6a2ecc0d29e | 516 | LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; |
tass | 0:b6a2ecc0d29e | 517 | |
tass | 0:b6a2ecc0d29e | 518 | // Tx Descriptors Point to index 0 |
tass | 0:b6a2ecc0d29e | 519 | LPC_EMAC->TxProduceIndex = 0; |
tass | 0:b6a2ecc0d29e | 520 | } |
tass | 0:b6a2ecc0d29e | 521 | |
tass | 0:b6a2ecc0d29e | 522 | |
tass | 0:b6a2ecc0d29e | 523 | // async send, returning amount of data sent, and 0 if the buffers are busy |
tass | 0:b6a2ecc0d29e | 524 | static int _emac_send_frame(struct pico_device *dev, void * buf, int len) |
tass | 0:b6a2ecc0d29e | 525 | { |
tass | 0:b6a2ecc0d29e | 526 | struct pico_device_mbed_emac *mbdev = (struct pico_device_mbed_emac *) dev; |
tass | 0:b6a2ecc0d29e | 527 | uint16_t size = len; |
tass | 0:b6a2ecc0d29e | 528 | uint32_t bufferIndex = LPC_EMAC->TxProduceIndex; |
tass | 0:b6a2ecc0d29e | 529 | uint16_t pSize = (size+1u)>>1u; |
tass | 0:b6a2ecc0d29e | 530 | uint16_t * data = (uint16_t *)buf; |
tass | 0:b6a2ecc0d29e | 531 | int data_sent = 0; |
tass | 0:b6a2ecc0d29e | 532 | |
tass | 0:b6a2ecc0d29e | 533 | // When TxProduceIndex == TxConsumeIndex, the transmit buffer is empty. |
tass | 0:b6a2ecc0d29e | 534 | // When TxProduceIndex == TxConsumeIndex -1 (taking wraparound into account), the transmit buffer is full! |
tass | 0:b6a2ecc0d29e | 535 | // We should check if there is still a tx_desc FREE!! Consume < Produce (wrapping!!) |
tass | 0:b6a2ecc0d29e | 536 | int cons = (int)LPC_EMAC->TxConsumeIndex; |
tass | 0:b6a2ecc0d29e | 537 | int prod = (int)LPC_EMAC->TxProduceIndex; |
tass | 0:b6a2ecc0d29e | 538 | int txfree = 0; |
tass | 0:b6a2ecc0d29e | 539 | |
tass | 0:b6a2ecc0d29e | 540 | if (prod == cons) |
tass | 0:b6a2ecc0d29e | 541 | txfree = NUM_TX_FRAG; |
tass | 0:b6a2ecc0d29e | 542 | else if (prod > cons) |
tass | 0:b6a2ecc0d29e | 543 | txfree = NUM_TX_FRAG - prod + cons - 1; |
tass | 0:b6a2ecc0d29e | 544 | else if (prod < cons) |
tass | 0:b6a2ecc0d29e | 545 | txfree = cons - prod - 1; |
tass | 0:b6a2ecc0d29e | 546 | |
tass | 0:b6a2ecc0d29e | 547 | if (txfree == 0) |
tass | 0:b6a2ecc0d29e | 548 | { |
tass | 8:0b675bdd074f | 549 | int retries = 2; |
tass | 8:0b675bdd074f | 550 | // block until an index gets free |
tass | 8:0b675bdd074f | 551 | while((LPC_EMAC->TxConsumeIndex -1)== LPC_EMAC->TxProduceIndex && (retries--)) |
tass | 8:0b675bdd074f | 552 | Thread::wait(1); |
tass | 8:0b675bdd074f | 553 | |
tass | 8:0b675bdd074f | 554 | if((LPC_EMAC->TxConsumeIndex -1)== LPC_EMAC->TxProduceIndex) |
tass | 8:0b675bdd074f | 555 | return 0; |
tass | 8:0b675bdd074f | 556 | else |
tass | 8:0b675bdd074f | 557 | bufferIndex = LPC_EMAC->TxProduceIndex; |
tass | 12:dc845268281a | 558 | //emac_dbg("p%i c%i stat:%d\r\n",prod,cons,LPC_EMAC->TxStatus); |
tass | 12:dc845268281a | 559 | //emac_dbg("Sending returned 0 : %x :%x\n",LPC_EMAC->IntStatus,LPC_EMAC->IntEnable); |
tass | 8:0b675bdd074f | 560 | |
tass | 0:b6a2ecc0d29e | 561 | } |
tass | 0:b6a2ecc0d29e | 562 | |
tass | 0:b6a2ecc0d29e | 563 | // set tx descriptors for send |
tass | 0:b6a2ecc0d29e | 564 | tptr = (uint16_t *)(mbdev->dma_data->p_tx_desc[bufferIndex].Packet); |
tass | 0:b6a2ecc0d29e | 565 | |
tass | 0:b6a2ecc0d29e | 566 | // copy data to AHB RAM (16-bit copies) |
tass | 0:b6a2ecc0d29e | 567 | while(pSize) |
tass | 0:b6a2ecc0d29e | 568 | { |
tass | 0:b6a2ecc0d29e | 569 | *tptr++ = *data++; |
tass | 0:b6a2ecc0d29e | 570 | pSize--; |
tass | 0:b6a2ecc0d29e | 571 | } |
tass | 0:b6a2ecc0d29e | 572 | |
tass | 0:b6a2ecc0d29e | 573 | data_sent = size; |
tass | 0:b6a2ecc0d29e | 574 | |
tass | 0:b6a2ecc0d29e | 575 | // send data, no interrupt needed I see, for now |
tass | 0:b6a2ecc0d29e | 576 | mbdev->dma_data->p_tx_desc[bufferIndex].Ctrl &= ~0x7FF; |
tass | 8:0b675bdd074f | 577 | mbdev->dma_data->p_tx_desc[bufferIndex].Ctrl = (((uint32_t)size -1) & 0x7FF) | TCTRL_INT | TCTRL_LAST; |
tass | 0:b6a2ecc0d29e | 578 | |
tass | 0:b6a2ecc0d29e | 579 | // advance the TxProduceIndex |
tass | 0:b6a2ecc0d29e | 580 | bufferIndex = (bufferIndex+1)%NUM_TX_FRAG; |
tass | 0:b6a2ecc0d29e | 581 | LPC_EMAC->TxProduceIndex = bufferIndex; |
tass | 0:b6a2ecc0d29e | 582 | |
tass | 0:b6a2ecc0d29e | 583 | // Toggle TX LED |
tass | 0:b6a2ecc0d29e | 584 | led_tx= !led_tx; |
tass | 0:b6a2ecc0d29e | 585 | |
tass | 0:b6a2ecc0d29e | 586 | return data_sent; |
tass | 0:b6a2ecc0d29e | 587 | } |
tass | 0:b6a2ecc0d29e | 588 | |
daniele | 5:50ba2a185f35 | 589 | |
tass | 0:b6a2ecc0d29e | 590 | /* polls for new data |
tass | 0:b6a2ecc0d29e | 591 | returns amount of bytes received -- 0 when no new data arrived */ |
tass | 0:b6a2ecc0d29e | 592 | static int _emac_poll(struct pico_device_mbed_emac * mbdev) |
tass | 0:b6a2ecc0d29e | 593 | { |
tass | 0:b6a2ecc0d29e | 594 | uint32_t index = LPC_EMAC->RxConsumeIndex; |
tass | 0:b6a2ecc0d29e | 595 | int retval = 0; |
tass | 0:b6a2ecc0d29e | 596 | |
tass | 0:b6a2ecc0d29e | 597 | // Consume all packets available |
tass | 0:b6a2ecc0d29e | 598 | while(index != LPC_EMAC->RxProduceIndex) |
tass | 0:b6a2ecc0d29e | 599 | { |
tass | 0:b6a2ecc0d29e | 600 | uint32_t info = mbdev->dma_data->p_rx_stat[index].Info; |
tass | 0:b6a2ecc0d29e | 601 | uint32_t RxLen = (info & RINFO_SIZE) - 3u; |
tass | 0:b6a2ecc0d29e | 602 | rptr = (uint16_t *)(mbdev->dma_data->p_rx_desc[index].Packet); |
tass | 0:b6a2ecc0d29e | 603 | |
tass | 7:608779751f85 | 604 | if(!( (RxLen >= ETH_MAX_MTU) || (info & RINFO_ERR_MASK) ) ) { |
daniele | 6:32c8501737cd | 605 | pico_stack_recv((struct pico_device *)mbdev,(uint8_t *)rptr,RxLen); |
tass | 0:b6a2ecc0d29e | 606 | } else { |
tass | 12:dc845268281a | 607 | //emac_dbg("RxError?\r\n"); |
tass | 0:b6a2ecc0d29e | 608 | } |
tass | 0:b6a2ecc0d29e | 609 | retval += RxLen; |
tass | 0:b6a2ecc0d29e | 610 | |
tass | 0:b6a2ecc0d29e | 611 | // Increment RxConsumeIndex |
tass | 0:b6a2ecc0d29e | 612 | index = (index+1)%NUM_RX_FRAG; |
tass | 0:b6a2ecc0d29e | 613 | LPC_EMAC->RxConsumeIndex = index; |
tass | 0:b6a2ecc0d29e | 614 | |
tass | 0:b6a2ecc0d29e | 615 | } |
tass | 0:b6a2ecc0d29e | 616 | |
tass | 0:b6a2ecc0d29e | 617 | return retval; |
tass | 0:b6a2ecc0d29e | 618 | } |
daniele | 5:50ba2a185f35 | 619 | |
tass | 0:b6a2ecc0d29e | 620 | static int _pico_emac_poll(struct pico_device *dev, int loop_score) |
tass | 0:b6a2ecc0d29e | 621 | { |
tass | 0:b6a2ecc0d29e | 622 | struct pico_device_mbed_emac *mb = (struct pico_device_mbed_emac *) dev; |
tass | 0:b6a2ecc0d29e | 623 | |
tass | 0:b6a2ecc0d29e | 624 | while(loop_score > 0) |
tass | 0:b6a2ecc0d29e | 625 | { |
tass | 0:b6a2ecc0d29e | 626 | // check for new frame(s) and send to pico stack |
tass | 0:b6a2ecc0d29e | 627 | // return loop_score if no frame has arrived |
tass | 0:b6a2ecc0d29e | 628 | if (!(_emac_poll(mb))) |
tass | 0:b6a2ecc0d29e | 629 | return loop_score; |
tass | 0:b6a2ecc0d29e | 630 | loop_score--; |
tass | 0:b6a2ecc0d29e | 631 | } |
tass | 0:b6a2ecc0d29e | 632 | return loop_score; |
tass | 0:b6a2ecc0d29e | 633 | } |
daniele | 5:50ba2a185f35 | 634 | |
tass | 0:b6a2ecc0d29e | 635 | |
tass | 0:b6a2ecc0d29e | 636 | /* Read PHY status */ |
tass | 0:b6a2ecc0d29e | 637 | static uint8_t _emac_update_phy_status(uint32_t linksts) |
tass | 0:b6a2ecc0d29e | 638 | { |
tass | 0:b6a2ecc0d29e | 639 | uint8_t changed = 0; |
tass | 0:b6a2ecc0d29e | 640 | static uint32_t oldlinksts = 0; |
tass | 0:b6a2ecc0d29e | 641 | |
tass | 0:b6a2ecc0d29e | 642 | if (oldlinksts != linksts) |
tass | 0:b6a2ecc0d29e | 643 | changed = 1; |
tass | 0:b6a2ecc0d29e | 644 | |
tass | 0:b6a2ecc0d29e | 645 | if (changed) |
tass | 0:b6a2ecc0d29e | 646 | { |
tass | 0:b6a2ecc0d29e | 647 | oldlinksts = linksts; |
tass | 0:b6a2ecc0d29e | 648 | |
tass | 0:b6a2ecc0d29e | 649 | // Update link active status |
tass | 0:b6a2ecc0d29e | 650 | if (linksts & DP8_VALID_LINK) |
tass | 0:b6a2ecc0d29e | 651 | { |
tass | 0:b6a2ecc0d29e | 652 | led_link = 1; |
tass | 12:dc845268281a | 653 | //emac_dbg("PHY> Link ACTIVE! --"); |
tass | 0:b6a2ecc0d29e | 654 | } |
tass | 0:b6a2ecc0d29e | 655 | else |
tass | 0:b6a2ecc0d29e | 656 | { |
tass | 0:b6a2ecc0d29e | 657 | led_link = 0; |
tass | 12:dc845268281a | 658 | //emac_dbg("PHY> Link inactive... --"); |
tass | 0:b6a2ecc0d29e | 659 | } |
tass | 0:b6a2ecc0d29e | 660 | |
tass | 0:b6a2ecc0d29e | 661 | // Full or half duplex |
tass | 0:b6a2ecc0d29e | 662 | if (linksts & DP8_FULLDUPLEX) |
tass | 12:dc845268281a | 663 | emac_dbg("Full duplex mode ! --"); |
tass | 0:b6a2ecc0d29e | 664 | else |
tass | 12:dc845268281a | 665 | emac_dbg("No full duplex...! --"); |
tass | 0:b6a2ecc0d29e | 666 | |
tass | 0:b6a2ecc0d29e | 667 | // Configure 100MBit/10MBit mode. |
tass | 0:b6a2ecc0d29e | 668 | if (linksts & DP8_SPEED10MBPS) |
tass | 12:dc845268281a | 669 | emac_dbg("@ 10 MBPS\r\n"); |
tass | 0:b6a2ecc0d29e | 670 | else |
tass | 12:dc845268281a | 671 | emac_dbg("@ 100 MBPS\r\n"); |
tass | 0:b6a2ecc0d29e | 672 | } |
tass | 0:b6a2ecc0d29e | 673 | |
tass | 0:b6a2ecc0d29e | 674 | return changed; |
tass | 0:b6a2ecc0d29e | 675 | } |
tass | 0:b6a2ecc0d29e | 676 | |
tass | 0:b6a2ecc0d29e | 677 | // Starts a read operation via the MII link (non-blocking) |
tass | 0:b6a2ecc0d29e | 678 | static void _emac_mii_read_noblock(uint32_t PhyReg) |
tass | 0:b6a2ecc0d29e | 679 | { |
tass | 0:b6a2ecc0d29e | 680 | // Read value at PHY address and register |
tass | 0:b6a2ecc0d29e | 681 | LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg; |
tass | 0:b6a2ecc0d29e | 682 | LPC_EMAC->MCMD = MCMD_READ; |
tass | 0:b6a2ecc0d29e | 683 | } |
tass | 0:b6a2ecc0d29e | 684 | |
tass | 0:b6a2ecc0d29e | 685 | /* Reads current MII link busy status */ |
tass | 0:b6a2ecc0d29e | 686 | static uint32_t _emac_mii_is_busy(void) |
tass | 0:b6a2ecc0d29e | 687 | { |
tass | 0:b6a2ecc0d29e | 688 | return (uint32_t) (LPC_EMAC->MIND & MIND_BUSY); |
tass | 0:b6a2ecc0d29e | 689 | } |
tass | 0:b6a2ecc0d29e | 690 | |
tass | 0:b6a2ecc0d29e | 691 | // Starts a read operation via the MII link (non-blocking) |
tass | 0:b6a2ecc0d29e | 692 | static uint32_t _emac_mii_read_data(void) |
tass | 0:b6a2ecc0d29e | 693 | { |
tass | 0:b6a2ecc0d29e | 694 | uint32_t data = LPC_EMAC->MRDD; |
tass | 0:b6a2ecc0d29e | 695 | LPC_EMAC->MCMD = 0; |
tass | 0:b6a2ecc0d29e | 696 | |
tass | 0:b6a2ecc0d29e | 697 | return data; |
tass | 0:b6a2ecc0d29e | 698 | } |
tass | 0:b6a2ecc0d29e | 699 | |
tass | 0:b6a2ecc0d29e | 700 | // Phy status update state machine |
tass | 0:b6a2ecc0d29e | 701 | static void _emac_phy_status(void const * dev) |
tass | 0:b6a2ecc0d29e | 702 | { |
tass | 0:b6a2ecc0d29e | 703 | static uint8_t phyustate = 0; |
tass | 0:b6a2ecc0d29e | 704 | uint32_t changed = 0; |
tass | 0:b6a2ecc0d29e | 705 | |
tass | 0:b6a2ecc0d29e | 706 | switch (phyustate) { |
tass | 0:b6a2ecc0d29e | 707 | default: |
tass | 0:b6a2ecc0d29e | 708 | case 0: |
tass | 0:b6a2ecc0d29e | 709 | // Read BMSR to clear faults |
tass | 0:b6a2ecc0d29e | 710 | _emac_mii_read_noblock(PHY_REG_STS); |
tass | 0:b6a2ecc0d29e | 711 | phyustate = 1; |
tass | 0:b6a2ecc0d29e | 712 | break; |
tass | 0:b6a2ecc0d29e | 713 | |
tass | 0:b6a2ecc0d29e | 714 | case 1: |
tass | 0:b6a2ecc0d29e | 715 | // Wait for read status state |
tass | 0:b6a2ecc0d29e | 716 | if (!_emac_mii_is_busy()) { |
tass | 0:b6a2ecc0d29e | 717 | // Update PHY status |
tass | 0:b6a2ecc0d29e | 718 | changed = _emac_update_phy_status(_emac_mii_read_data()); |
tass | 0:b6a2ecc0d29e | 719 | phyustate = 0; |
tass | 0:b6a2ecc0d29e | 720 | } |
tass | 0:b6a2ecc0d29e | 721 | break; |
tass | 0:b6a2ecc0d29e | 722 | } |
tass | 0:b6a2ecc0d29e | 723 | } |