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