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