Enables fast realtime communication over Ethernet by using plain Ethernet frames (overhead of TCP/IP network layers is stripped away).

Dependents:   RawEthernet_Hello

Committer:
hudakz
Date:
Mon Aug 20 11:37:35 2018 +0000
Revision:
0:ca476e0a1a28
Initial release.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:ca476e0a1a28 1 //------------------------------------------------------------------------------
hudakz 0:ca476e0a1a28 2 // Functions for using an ENC28J60 ethernet controller, optimized for
hudakz 0:ca476e0a1a28 3 // communication speed.
hudakz 0:ca476e0a1a28 4 //
hudakz 0:ca476e0a1a28 5 // Written by Rogier Schouten http://www.rogiershikes.tk
hudakz 0:ca476e0a1a28 6 // Based on code by Guido Socher http://www.tuxgraphics.org
hudakz 0:ca476e0a1a28 7 // Idea modified and further updated by Guido Socher
hudakz 0:ca476e0a1a28 8 // Ported to MBED by Zoltan Hudak hudakz@outlook.com
hudakz 0:ca476e0a1a28 9 // License: GPL V2
hudakz 0:ca476e0a1a28 10 //
hudakz 0:ca476e0a1a28 11 // Enables to read sensor data or control IO-ports with less than a millisecond delay.
hudakz 0:ca476e0a1a28 12 // The trick is in removing the TCP/IP overhead and use raw Ethernet frames.
hudakz 0:ca476e0a1a28 13 // A Linux application using raw network sockets is controlling this slave device.
hudakz 0:ca476e0a1a28 14 //
hudakz 0:ca476e0a1a28 15 // Assumptions:
hudakz 0:ca476e0a1a28 16 // - Max. payload data: 255 bytes per packet
hudakz 0:ca476e0a1a28 17 // - The network consists of a master PC and one or more slave devices.
hudakz 0:ca476e0a1a28 18 // Only plain hubs and switches are allowed between PC and ethernet device.
hudakz 0:ca476e0a1a28 19 // Note that some wlan routers have internal switches which switch only
hudakz 0:ca476e0a1a28 20 // IP packets. They will discard plain ethernet frames. A normal 100Mbit
hudakz 0:ca476e0a1a28 21 // office/workgroup switch will however work.
hudakz 0:ca476e0a1a28 22 //
hudakz 0:ca476e0a1a28 23 // Based on these assumptions, we can optimize the protocol for faster communication:
hudakz 0:ca476e0a1a28 24 // - Master and slave send unicast packets.
hudakz 0:ca476e0a1a28 25 // - We use raw ethernet and no higher-level protocol such as UDP or TCP/IP
hudakz 0:ca476e0a1a28 26 // - We use the EtherType field of a packet as a length field. Actually, we only
hudakz 0:ca476e0a1a28 27 // use one byte of it since we have max 255 length packets.
hudakz 0:ca476e0a1a28 28 //
hudakz 0:ca476e0a1a28 29 // Furthermore, there are a few code optimizations:
hudakz 0:ca476e0a1a28 30 // - Minimize communication between ENC and MCU.
hudakz 0:ca476e0a1a28 31 // - No unnecessary memory bank checks
hudakz 0:ca476e0a1a28 32 //
hudakz 0:ca476e0a1a28 33 #include "RawEthernet.h"
hudakz 0:ca476e0a1a28 34
hudakz 0:ca476e0a1a28 35 // ENC28J60 Control Registers
hudakz 0:ca476e0a1a28 36
hudakz 0:ca476e0a1a28 37 // Control register definitions are a combination of address,
hudakz 0:ca476e0a1a28 38 // bank number, and Ethernet/MAC/PHY indicator bits.
hudakz 0:ca476e0a1a28 39 // - Register address (bits 0-4)
hudakz 0:ca476e0a1a28 40 // - Bank number (bits 5-6)
hudakz 0:ca476e0a1a28 41 // - MAC/PHY indicator (bit 7)
hudakz 0:ca476e0a1a28 42 #define ADDR_MASK 0x1F
hudakz 0:ca476e0a1a28 43 #define BANK_MASK 0x60
hudakz 0:ca476e0a1a28 44 #define SPRD_MASK 0x80
hudakz 0:ca476e0a1a28 45 // All-bank registers
hudakz 0:ca476e0a1a28 46 #define EIE 0x1B
hudakz 0:ca476e0a1a28 47 #define EIR 0x1C
hudakz 0:ca476e0a1a28 48 #define ESTAT 0x1D
hudakz 0:ca476e0a1a28 49 #define ECON2 0x1E
hudakz 0:ca476e0a1a28 50 #define ECON1 0x1F
hudakz 0:ca476e0a1a28 51 // Bank 0 registers
hudakz 0:ca476e0a1a28 52 #define ERDPTL (0x00 | 0x00)
hudakz 0:ca476e0a1a28 53 #define ERDPTH (0x01 | 0x00)
hudakz 0:ca476e0a1a28 54 #define EWRPTL (0x02 | 0x00)
hudakz 0:ca476e0a1a28 55 #define EWRPTH (0x03 | 0x00)
hudakz 0:ca476e0a1a28 56 #define ETXSTL (0x04 | 0x00)
hudakz 0:ca476e0a1a28 57 #define ETXSTH (0x05 | 0x00)
hudakz 0:ca476e0a1a28 58 #define ETXNDL (0x06 | 0x00)
hudakz 0:ca476e0a1a28 59 #define ETXNDH (0x07 | 0x00)
hudakz 0:ca476e0a1a28 60 #define ERXSTL (0x08 | 0x00)
hudakz 0:ca476e0a1a28 61 #define ERXSTH (0x09 | 0x00)
hudakz 0:ca476e0a1a28 62 #define ERXNDL (0x0A | 0x00)
hudakz 0:ca476e0a1a28 63 #define ERXNDH (0x0B | 0x00)
hudakz 0:ca476e0a1a28 64 #define ERXRDPTL (0x0C | 0x00)
hudakz 0:ca476e0a1a28 65 #define ERXRDPTH (0x0D | 0x00)
hudakz 0:ca476e0a1a28 66 #define ERXWRPTL (0x0E | 0x00)
hudakz 0:ca476e0a1a28 67 #define ERXWRPTH (0x0F | 0x00)
hudakz 0:ca476e0a1a28 68 #define EDMASTL (0x10 | 0x00)
hudakz 0:ca476e0a1a28 69 #define EDMASTH (0x11 | 0x00)
hudakz 0:ca476e0a1a28 70 #define EDMANDL (0x12 | 0x00)
hudakz 0:ca476e0a1a28 71 #define EDMANDH (0x13 | 0x00)
hudakz 0:ca476e0a1a28 72 #define EDMADSTL (0x14 | 0x00)
hudakz 0:ca476e0a1a28 73 #define EDMADSTH (0x15 | 0x00)
hudakz 0:ca476e0a1a28 74 #define EDMACSL (0x16 | 0x00)
hudakz 0:ca476e0a1a28 75 #define EDMACSH (0x17 | 0x00)
hudakz 0:ca476e0a1a28 76 // Bank 1 registers
hudakz 0:ca476e0a1a28 77 #define EHT0 (0x00 | 0x20)
hudakz 0:ca476e0a1a28 78 #define EHT1 (0x01 | 0x20)
hudakz 0:ca476e0a1a28 79 #define EHT2 (0x02 | 0x20)
hudakz 0:ca476e0a1a28 80 #define EHT3 (0x03 | 0x20)
hudakz 0:ca476e0a1a28 81 #define EHT4 (0x04 | 0x20)
hudakz 0:ca476e0a1a28 82 #define EHT5 (0x05 | 0x20)
hudakz 0:ca476e0a1a28 83 #define EHT6 (0x06 | 0x20)
hudakz 0:ca476e0a1a28 84 #define EHT7 (0x07 | 0x20)
hudakz 0:ca476e0a1a28 85 #define EPMM0 (0x08 | 0x20)
hudakz 0:ca476e0a1a28 86 #define EPMM1 (0x09 | 0x20)
hudakz 0:ca476e0a1a28 87 #define EPMM2 (0x0A | 0x20)
hudakz 0:ca476e0a1a28 88 #define EPMM3 (0x0B | 0x20)
hudakz 0:ca476e0a1a28 89 #define EPMM4 (0x0C | 0x20)
hudakz 0:ca476e0a1a28 90 #define EPMM5 (0x0D | 0x20)
hudakz 0:ca476e0a1a28 91 #define EPMM6 (0x0E | 0x20)
hudakz 0:ca476e0a1a28 92 #define EPMM7 (0x0F | 0x20)
hudakz 0:ca476e0a1a28 93 #define EPMCSL (0x10 | 0x20)
hudakz 0:ca476e0a1a28 94 #define EPMCSH (0x11 | 0x20)
hudakz 0:ca476e0a1a28 95 #define EPMOL (0x14 | 0x20)
hudakz 0:ca476e0a1a28 96 #define EPMOH (0x15 | 0x20)
hudakz 0:ca476e0a1a28 97 #define EWOLIE (0x16 | 0x20)
hudakz 0:ca476e0a1a28 98 #define EWOLIR (0x17 | 0x20)
hudakz 0:ca476e0a1a28 99 #define ERXFCON (0x18 | 0x20)
hudakz 0:ca476e0a1a28 100 #define EPKTCNT (0x19 | 0x20)
hudakz 0:ca476e0a1a28 101 // Bank 2 registers
hudakz 0:ca476e0a1a28 102 #define MACON1 (0x00 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 103 #define MACON2 (0x01 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 104 #define MACON3 (0x02 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 105 #define MACON4 (0x03 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 106 #define MABBIPG (0x04 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 107 #define MAIPGL (0x06 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 108 #define MAIPGH (0x07 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 109 #define MACLCON1 (0x08 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 110 #define MACLCON2 (0x09 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 111 #define MAMXFLL (0x0A | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 112 #define MAMXFLH (0x0B | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 113 #define MAPHSUP (0x0D | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 114 #define MICON (0x11 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 115 #define MICMD (0x12 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 116 #define MIREGADR (0x14 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 117 #define MIWRL (0x16 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 118 #define MIWRH (0x17 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 119 #define MIRDL (0x18 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 120 #define MIRDH (0x19 | 0x40 | 0x80)
hudakz 0:ca476e0a1a28 121 // Bank 3 registers
hudakz 0:ca476e0a1a28 122 #define MAADR1 (0x00 | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 123 #define MAADR0 (0x01 | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 124 #define MAADR3 (0x02 | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 125 #define MAADR2 (0x03 | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 126 #define MAADR5 (0x04 | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 127 #define MAADR4 (0x05 | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 128 #define EBSTSD (0x06 | 0x60)
hudakz 0:ca476e0a1a28 129 #define EBSTCON (0x07 | 0x60)
hudakz 0:ca476e0a1a28 130 #define EBSTCSL (0x08 | 0x60)
hudakz 0:ca476e0a1a28 131 #define EBSTCSH (0x09 | 0x60)
hudakz 0:ca476e0a1a28 132 #define MISTAT (0x0A | 0x60 | 0x80)
hudakz 0:ca476e0a1a28 133 #define EREVID (0x12 | 0x60)
hudakz 0:ca476e0a1a28 134 #define ECOCON (0x15 | 0x60)
hudakz 0:ca476e0a1a28 135 #define EFLOCON (0x17 | 0x60)
hudakz 0:ca476e0a1a28 136 #define EPAUSL (0x18 | 0x60)
hudakz 0:ca476e0a1a28 137 #define EPAUSH (0x19 | 0x60)
hudakz 0:ca476e0a1a28 138 // PHY registers
hudakz 0:ca476e0a1a28 139 #define PHCON1 0x00
hudakz 0:ca476e0a1a28 140 #define PHSTAT1 0x01
hudakz 0:ca476e0a1a28 141 #define PHHID1 0x02
hudakz 0:ca476e0a1a28 142 #define PHHID2 0x03
hudakz 0:ca476e0a1a28 143 #define PHCON2 0x10
hudakz 0:ca476e0a1a28 144 #define PHSTAT2 0x11
hudakz 0:ca476e0a1a28 145 #define PHIE 0x12
hudakz 0:ca476e0a1a28 146 #define PHIR 0x13
hudakz 0:ca476e0a1a28 147 #define PHLCON 0x14
hudakz 0:ca476e0a1a28 148 // ENC28J60 ERXFCON Register Bit Definitions
hudakz 0:ca476e0a1a28 149 #define ERXFCON_UCEN 0x80
hudakz 0:ca476e0a1a28 150 #define ERXFCON_ANDOR 0x40
hudakz 0:ca476e0a1a28 151 #define ERXFCON_CRCEN 0x20
hudakz 0:ca476e0a1a28 152 #define ERXFCON_PMEN 0x10
hudakz 0:ca476e0a1a28 153 #define ERXFCON_MPEN 0x08
hudakz 0:ca476e0a1a28 154 #define ERXFCON_HTEN 0x04
hudakz 0:ca476e0a1a28 155 #define ERXFCON_MCEN 0x02
hudakz 0:ca476e0a1a28 156 #define ERXFCON_BCEN 0x01
hudakz 0:ca476e0a1a28 157 // ENC28J60 EIE Register Bit Definitions
hudakz 0:ca476e0a1a28 158 #define EIE_INTIE 0x80
hudakz 0:ca476e0a1a28 159 #define EIE_PKTIE 0x40
hudakz 0:ca476e0a1a28 160 #define EIE_DMAIE 0x20
hudakz 0:ca476e0a1a28 161 #define EIE_LINKIE 0x10
hudakz 0:ca476e0a1a28 162 #define EIE_TXIE 0x08
hudakz 0:ca476e0a1a28 163 #define EIE_WOLIE 0x04
hudakz 0:ca476e0a1a28 164 #define EIE_TXERIE 0x02
hudakz 0:ca476e0a1a28 165 #define EIE_RXERIE 0x01
hudakz 0:ca476e0a1a28 166 // ENC28J60 EIR Register Bit Definitions
hudakz 0:ca476e0a1a28 167 #define EIR_PKTIF 0x40
hudakz 0:ca476e0a1a28 168 #define EIR_DMAIF 0x20
hudakz 0:ca476e0a1a28 169 #define EIR_LINKIF 0x10
hudakz 0:ca476e0a1a28 170 #define EIR_TXIF 0x08
hudakz 0:ca476e0a1a28 171 #define EIR_WOLIF 0x04
hudakz 0:ca476e0a1a28 172 #define EIR_TXERIF 0x02
hudakz 0:ca476e0a1a28 173 #define EIR_RXERIF 0x01
hudakz 0:ca476e0a1a28 174 // ENC28J60 ESTAT Register Bit Definitions
hudakz 0:ca476e0a1a28 175 #define ESTAT_INT 0x80
hudakz 0:ca476e0a1a28 176 #define ESTAT_LATECOL 0x10
hudakz 0:ca476e0a1a28 177 #define ESTAT_RXBUSY 0x04
hudakz 0:ca476e0a1a28 178 #define ESTAT_TXABRT 0x02
hudakz 0:ca476e0a1a28 179 #define ESTAT_CLKRDY 0x01
hudakz 0:ca476e0a1a28 180 // ENC28J60 ECON2 Register Bit Definitions
hudakz 0:ca476e0a1a28 181 #define ECON2_AUTOINC 0x80
hudakz 0:ca476e0a1a28 182 #define ECON2_PKTDEC 0x40
hudakz 0:ca476e0a1a28 183 #define ECON2_PWRSV 0x20
hudakz 0:ca476e0a1a28 184 #define ECON2_VRPS 0x08
hudakz 0:ca476e0a1a28 185 // ENC28J60 ECON1 Register Bit Definitions
hudakz 0:ca476e0a1a28 186 #define ECON1_TXRST 0x80
hudakz 0:ca476e0a1a28 187 #define ECON1_RXRST 0x40
hudakz 0:ca476e0a1a28 188 #define ECON1_DMAST 0x20
hudakz 0:ca476e0a1a28 189 #define ECON1_CSUMEN 0x10
hudakz 0:ca476e0a1a28 190 #define ECON1_TXRTS 0x08
hudakz 0:ca476e0a1a28 191 #define ECON1_RXEN 0x04
hudakz 0:ca476e0a1a28 192 #define ECON1_BSEL1 0x02
hudakz 0:ca476e0a1a28 193 #define ECON1_BSEL0 0x01
hudakz 0:ca476e0a1a28 194 // ENC28J60 MACON1 Register Bit Definitions
hudakz 0:ca476e0a1a28 195 #define MACON1_LOOPBK 0x10
hudakz 0:ca476e0a1a28 196 #define MACON1_TXPAUS 0x08
hudakz 0:ca476e0a1a28 197 #define MACON1_RXPAUS 0x04
hudakz 0:ca476e0a1a28 198 #define MACON1_PASSALL 0x02
hudakz 0:ca476e0a1a28 199 #define MACON1_MARXEN 0x01
hudakz 0:ca476e0a1a28 200 // ENC28J60 MACON2 Register Bit Definitions
hudakz 0:ca476e0a1a28 201 #define MACON2_MARST 0x80
hudakz 0:ca476e0a1a28 202 #define MACON2_RNDRST 0x40
hudakz 0:ca476e0a1a28 203 #define MACON2_MARXRST 0x08
hudakz 0:ca476e0a1a28 204 #define MACON2_RFUNRST 0x04
hudakz 0:ca476e0a1a28 205 #define MACON2_MATXRST 0x02
hudakz 0:ca476e0a1a28 206 #define MACON2_TFUNRST 0x01
hudakz 0:ca476e0a1a28 207 // ENC28J60 MACON3 Register Bit Definitions
hudakz 0:ca476e0a1a28 208 #define MACON3_PADCFG2 0x80
hudakz 0:ca476e0a1a28 209 #define MACON3_PADCFG1 0x40
hudakz 0:ca476e0a1a28 210 #define MACON3_PADCFG0 0x20
hudakz 0:ca476e0a1a28 211 #define MACON3_TXCRCEN 0x10
hudakz 0:ca476e0a1a28 212 #define MACON3_PHDRLEN 0x08
hudakz 0:ca476e0a1a28 213 #define MACON3_HFRMLEN 0x04
hudakz 0:ca476e0a1a28 214 #define MACON3_FRMLNEN 0x02
hudakz 0:ca476e0a1a28 215 #define MACON3_FULDPX 0x01
hudakz 0:ca476e0a1a28 216 // ENC28J60 MACON4 Register Bit Definitions
hudakz 0:ca476e0a1a28 217 #define MACON4_DEFER 0x40
hudakz 0:ca476e0a1a28 218 #define MACON4_BPEN 0x20
hudakz 0:ca476e0a1a28 219 #define MACON4_NOBKOFF 0x10
hudakz 0:ca476e0a1a28 220 // ENC28J60 MICMD Register Bit Definitions
hudakz 0:ca476e0a1a28 221 #define MICMD_MIISCAN 0x02
hudakz 0:ca476e0a1a28 222 #define MICMD_MIIRD 0x01
hudakz 0:ca476e0a1a28 223 // ENC28J60 MISTAT Register Bit Definitions
hudakz 0:ca476e0a1a28 224 #define MISTAT_NVALID 0x04
hudakz 0:ca476e0a1a28 225 #define MISTAT_SCAN 0x02
hudakz 0:ca476e0a1a28 226 #define MISTAT_BUSY 0x01
hudakz 0:ca476e0a1a28 227 // ENC28J60 PHY PHCON1 Register Bit Definitions
hudakz 0:ca476e0a1a28 228 #define PHCON1_PRST 0x8000
hudakz 0:ca476e0a1a28 229 #define PHCON1_PLOOPBK 0x4000
hudakz 0:ca476e0a1a28 230 #define PHCON1_PPWRSV 0x0800
hudakz 0:ca476e0a1a28 231 #define PHCON1_PDPXMD 0x0100
hudakz 0:ca476e0a1a28 232 // ENC28J60 PHY PHSTAT1 Register Bit Definitions
hudakz 0:ca476e0a1a28 233 #define PHSTAT1_PFDPX 0x1000
hudakz 0:ca476e0a1a28 234 #define PHSTAT1_PHDPX 0x0800
hudakz 0:ca476e0a1a28 235 #define PHSTAT1_LLSTAT 0x0004
hudakz 0:ca476e0a1a28 236 #define PHSTAT1_JBSTAT 0x0002
hudakz 0:ca476e0a1a28 237 // ENC28J60 PHY PHSTAT2H Register Bit Definitions
hudakz 0:ca476e0a1a28 238 #define PHSTAT2H_LSTAT 0x04
hudakz 0:ca476e0a1a28 239 // ENC28J60 PHY PHCON2 Register Bit Definitions
hudakz 0:ca476e0a1a28 240 #define PHCON2_FRCLINK 0x4000
hudakz 0:ca476e0a1a28 241 #define PHCON2_TXDIS 0x2000
hudakz 0:ca476e0a1a28 242 #define PHCON2_JABBER 0x0400
hudakz 0:ca476e0a1a28 243 #define PHCON2_HDLDIS 0x0100
hudakz 0:ca476e0a1a28 244 // ENC28J60 Packet Control Byte Bit Definitions
hudakz 0:ca476e0a1a28 245 #define PKTCTRL_PHUGEEN 0x08
hudakz 0:ca476e0a1a28 246 #define PKTCTRL_PPADEN 0x04
hudakz 0:ca476e0a1a28 247 #define PKTCTRL_PCRCEN 0x02
hudakz 0:ca476e0a1a28 248 #define PKTCTRL_POVERRIDE 0x01
hudakz 0:ca476e0a1a28 249 // SPI operation codes
hudakz 0:ca476e0a1a28 250 #define ENC28J60_READ_CTRL_REG 0x00
hudakz 0:ca476e0a1a28 251 #define ENC28J60_READ_BUF_MEM 0x3A
hudakz 0:ca476e0a1a28 252 #define ENC28J60_WRITE_CTRL_REG 0x40
hudakz 0:ca476e0a1a28 253 #define ENC28J60_WRITE_BUF_MEM 0x7A
hudakz 0:ca476e0a1a28 254 #define ENC28J60_BIT_FIELD_SET 0x80
hudakz 0:ca476e0a1a28 255 #define ENC28J60_BIT_FIELD_CLR 0xA0
hudakz 0:ca476e0a1a28 256 #define ENC28J60_SOFT_RESET 0xFF
hudakz 0:ca476e0a1a28 257 // Buffer memory allocation within controlller.
hudakz 0:ca476e0a1a28 258 // Assuming the controller is slower than the network, we allocate one transmit
hudakz 0:ca476e0a1a28 259 // packet and leave the rest for receiving.
hudakz 0:ca476e0a1a28 260 // The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
hudakz 0:ca476e0a1a28 261 #define RXSTART_INIT 0x0
hudakz 0:ca476e0a1a28 262 #define RXSTOP_INIT (0x1FFF - 0x0600 - 2) // note: MUST be odd (see errata point 13)
hudakz 0:ca476e0a1a28 263 #define TXSTART_INIT (0x1FFF - 0x0600)
hudakz 0:ca476e0a1a28 264 // Maximum packet length: this software has a limit of 255 payload data bytes
hudakz 0:ca476e0a1a28 265 // and then there is some ethernet overhead (srd, dst, len, fcs)
hudakz 0:ca476e0a1a28 266 #define ENC28J60_MAX_PACKET_LEN ((uint16_t) 273)
hudakz 0:ca476e0a1a28 267 // field or packet lengths
hudakz 0:ca476e0a1a28 268 #define ETH_HEADER_LEN 14
hudakz 0:ca476e0a1a28 269 #define ETH_CHECKSUM_LEN 4
hudakz 0:ca476e0a1a28 270 #define ETH_ENVELOPE_LEN (ETH_HEADER_LEN + ETH_CHECKSUM_LEN)
hudakz 0:ca476e0a1a28 271 #define ETH_PAYLOAD_MIN 46
hudakz 0:ca476e0a1a28 272 #define ETH_PAYLOAD_MAX 1500
hudakz 0:ca476e0a1a28 273 #define ETH_PACKET_MIN 64
hudakz 0:ca476e0a1a28 274 #define ETH_PACKET_MAX 1518
hudakz 0:ca476e0a1a28 275 // field locations in ethernet packet
hudakz 0:ca476e0a1a28 276 #define ETH_DST_MAC_P 0
hudakz 0:ca476e0a1a28 277 #define ETH_SRC_MAC_P 6
hudakz 0:ca476e0a1a28 278 #define ETH_TYPE_H_P 12
hudakz 0:ca476e0a1a28 279 #define ETH_TYPE_L_P 13
hudakz 0:ca476e0a1a28 280 #define ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT
hudakz 0:ca476e0a1a28 281
hudakz 0:ca476e0a1a28 282 /* Static member initialization */
hudakz 0:ca476e0a1a28 283 char RawEthernet::_arpReqHdr[10] = { 8, 6, 0, 1, 8, 0, 6, 4, 0, 1 };
hudakz 0:ca476e0a1a28 284
hudakz 0:ca476e0a1a28 285 /**
hudakz 0:ca476e0a1a28 286 * @brief Constructor
hudakz 0:ca476e0a1a28 287 * @note
hudakz 0:ca476e0a1a28 288 * @param mosi SPI master-out slave-in pin #
hudakz 0:ca476e0a1a28 289 * @param miso SPI master-in slave-out pin #
hudakz 0:ca476e0a1a28 290 * @param sclk SPI serial clock pin #
hudakz 0:ca476e0a1a28 291 * @param cs SPI chip select pin #
hudakz 0:ca476e0a1a28 292 * @retval
hudakz 0:ca476e0a1a28 293 */
hudakz 0:ca476e0a1a28 294 RawEthernet::RawEthernet(PinName mosi, PinName miso, PinName sclk, PinName cs, uint8_t myMac[6], uint8_t myIp[4]) :
hudakz 0:ca476e0a1a28 295 _spi(mosi, miso, sclk),
hudakz 0:ca476e0a1a28 296 _cs(cs)
hudakz 0:ca476e0a1a28 297 {
hudakz 0:ca476e0a1a28 298 int i;
hudakz 0:ca476e0a1a28 299
hudakz 0:ca476e0a1a28 300 for (i = 0; i < 6; i++)
hudakz 0:ca476e0a1a28 301 _mac[i] = myMac[i];
hudakz 0:ca476e0a1a28 302
hudakz 0:ca476e0a1a28 303 for (i = 0; i < 4; i++)
hudakz 0:ca476e0a1a28 304 _ip[i] = myIp[i];
hudakz 0:ca476e0a1a28 305 }
hudakz 0:ca476e0a1a28 306
hudakz 0:ca476e0a1a28 307 /**
hudakz 0:ca476e0a1a28 308 * @brief Read operation
hudakz 0:ca476e0a1a28 309 * @note Reads from ENC28J60 register
hudakz 0:ca476e0a1a28 310 * @param op operation code
hudakz 0:ca476e0a1a28 311 * @param address register address
hudakz 0:ca476e0a1a28 312 * @retval Register value
hudakz 0:ca476e0a1a28 313 */
hudakz 0:ca476e0a1a28 314 uint8_t RawEthernet::readOp(uint8_t op, uint8_t address)
hudakz 0:ca476e0a1a28 315 {
hudakz 0:ca476e0a1a28 316 uint8_t result;
hudakz 0:ca476e0a1a28 317
hudakz 0:ca476e0a1a28 318 _cs = 0;
hudakz 0:ca476e0a1a28 319
hudakz 0:ca476e0a1a28 320 // issue read command
hudakz 0:ca476e0a1a28 321 _spi.write(op | (address & ADDR_MASK));
hudakz 0:ca476e0a1a28 322
hudakz 0:ca476e0a1a28 323 // read data
hudakz 0:ca476e0a1a28 324 result = _spi.write(0x00);
hudakz 0:ca476e0a1a28 325
hudakz 0:ca476e0a1a28 326 // do dummy read if needed (for mac and mii, see datasheet page 29)
hudakz 0:ca476e0a1a28 327 if (address & 0x80)
hudakz 0:ca476e0a1a28 328 result = _spi.write(0x00);
hudakz 0:ca476e0a1a28 329
hudakz 0:ca476e0a1a28 330 // release CS
hudakz 0:ca476e0a1a28 331 _cs = 1;
hudakz 0:ca476e0a1a28 332 return(result);
hudakz 0:ca476e0a1a28 333 }
hudakz 0:ca476e0a1a28 334
hudakz 0:ca476e0a1a28 335 /**
hudakz 0:ca476e0a1a28 336 * @brief Write operation
hudakz 0:ca476e0a1a28 337 * @note Writes to ENC28J60 register
hudakz 0:ca476e0a1a28 338 * @param op operation code
hudakz 0:ca476e0a1a28 339 * @param address register address
hudakz 0:ca476e0a1a28 340 * @retval data data to be written
hudakz 0:ca476e0a1a28 341 */
hudakz 0:ca476e0a1a28 342 void RawEthernet::writeOp(uint8_t op, uint8_t address, uint8_t data)
hudakz 0:ca476e0a1a28 343 {
hudakz 0:ca476e0a1a28 344 _cs = 0;
hudakz 0:ca476e0a1a28 345
hudakz 0:ca476e0a1a28 346 // issue write command
hudakz 0:ca476e0a1a28 347 _spi.write(op | (address & ADDR_MASK));
hudakz 0:ca476e0a1a28 348
hudakz 0:ca476e0a1a28 349 // write data
hudakz 0:ca476e0a1a28 350 _spi.write(data);
hudakz 0:ca476e0a1a28 351 _cs = 1;
hudakz 0:ca476e0a1a28 352 }
hudakz 0:ca476e0a1a28 353
hudakz 0:ca476e0a1a28 354 /**
hudakz 0:ca476e0a1a28 355 * @brief
hudakz 0:ca476e0a1a28 356 * @note
hudakz 0:ca476e0a1a28 357 * @param
hudakz 0:ca476e0a1a28 358 * @retval
hudakz 0:ca476e0a1a28 359 */
hudakz 0:ca476e0a1a28 360 void RawEthernet::setBank(uint8_t address)
hudakz 0:ca476e0a1a28 361 {
hudakz 0:ca476e0a1a28 362 // set the bank (if needed)
hudakz 0:ca476e0a1a28 363 if ((address & BANK_MASK) != _bank) {
hudakz 0:ca476e0a1a28 364 // set the bank
hudakz 0:ca476e0a1a28 365 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
hudakz 0:ca476e0a1a28 366 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
hudakz 0:ca476e0a1a28 367 _bank = (address & BANK_MASK);
hudakz 0:ca476e0a1a28 368 }
hudakz 0:ca476e0a1a28 369 }
hudakz 0:ca476e0a1a28 370
hudakz 0:ca476e0a1a28 371 /**
hudakz 0:ca476e0a1a28 372 * @brief
hudakz 0:ca476e0a1a28 373 * @note
hudakz 0:ca476e0a1a28 374 * @param
hudakz 0:ca476e0a1a28 375 * @retval
hudakz 0:ca476e0a1a28 376 */
hudakz 0:ca476e0a1a28 377 uint8_t RawEthernet::readReg(uint8_t address)
hudakz 0:ca476e0a1a28 378 {
hudakz 0:ca476e0a1a28 379 setBank(address);
hudakz 0:ca476e0a1a28 380 readOp(ENC28J60_READ_CTRL_REG, address);
hudakz 0:ca476e0a1a28 381 }
hudakz 0:ca476e0a1a28 382
hudakz 0:ca476e0a1a28 383 /**
hudakz 0:ca476e0a1a28 384 * @brief
hudakz 0:ca476e0a1a28 385 * @note
hudakz 0:ca476e0a1a28 386 * @param
hudakz 0:ca476e0a1a28 387 * @retval
hudakz 0:ca476e0a1a28 388 */
hudakz 0:ca476e0a1a28 389 void RawEthernet::writeReg(uint8_t address, uint8_t data)
hudakz 0:ca476e0a1a28 390 {
hudakz 0:ca476e0a1a28 391 setBank(address);
hudakz 0:ca476e0a1a28 392 writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
hudakz 0:ca476e0a1a28 393 }
hudakz 0:ca476e0a1a28 394
hudakz 0:ca476e0a1a28 395 /**
hudakz 0:ca476e0a1a28 396 * @brief
hudakz 0:ca476e0a1a28 397 * @note
hudakz 0:ca476e0a1a28 398 * @param
hudakz 0:ca476e0a1a28 399 * @retval
hudakz 0:ca476e0a1a28 400 */
hudakz 0:ca476e0a1a28 401 void RawEthernet::readBuffer(uint16_t len, uint8_t* data)
hudakz 0:ca476e0a1a28 402 {
hudakz 0:ca476e0a1a28 403 _cs = 0;
hudakz 0:ca476e0a1a28 404
hudakz 0:ca476e0a1a28 405 // issue read command
hudakz 0:ca476e0a1a28 406 _spi.write(ENC28J60_READ_BUF_MEM);
hudakz 0:ca476e0a1a28 407 while (len) {
hudakz 0:ca476e0a1a28 408 len--;
hudakz 0:ca476e0a1a28 409
hudakz 0:ca476e0a1a28 410 // read data
hudakz 0:ca476e0a1a28 411 *data = _spi.write(0x00);
hudakz 0:ca476e0a1a28 412 data++;
hudakz 0:ca476e0a1a28 413 }
hudakz 0:ca476e0a1a28 414
hudakz 0:ca476e0a1a28 415 //*data = '\0';
hudakz 0:ca476e0a1a28 416 _cs = 1;
hudakz 0:ca476e0a1a28 417 }
hudakz 0:ca476e0a1a28 418
hudakz 0:ca476e0a1a28 419 /**
hudakz 0:ca476e0a1a28 420 * @brief
hudakz 0:ca476e0a1a28 421 * @note
hudakz 0:ca476e0a1a28 422 * @param
hudakz 0:ca476e0a1a28 423 * @retval
hudakz 0:ca476e0a1a28 424 */
hudakz 0:ca476e0a1a28 425 void RawEthernet::writeBuffer(uint16_t len, uint8_t* data)
hudakz 0:ca476e0a1a28 426 {
hudakz 0:ca476e0a1a28 427 _cs = 0;
hudakz 0:ca476e0a1a28 428
hudakz 0:ca476e0a1a28 429 // issue write command
hudakz 0:ca476e0a1a28 430 _spi.write(ENC28J60_WRITE_BUF_MEM);
hudakz 0:ca476e0a1a28 431 while (len) {
hudakz 0:ca476e0a1a28 432 len--;
hudakz 0:ca476e0a1a28 433
hudakz 0:ca476e0a1a28 434 // write data
hudakz 0:ca476e0a1a28 435 _spi.write(*data);
hudakz 0:ca476e0a1a28 436 data++;
hudakz 0:ca476e0a1a28 437 }
hudakz 0:ca476e0a1a28 438
hudakz 0:ca476e0a1a28 439 _cs = 1;
hudakz 0:ca476e0a1a28 440 }
hudakz 0:ca476e0a1a28 441
hudakz 0:ca476e0a1a28 442 /**
hudakz 0:ca476e0a1a28 443 * @brief
hudakz 0:ca476e0a1a28 444 * @note
hudakz 0:ca476e0a1a28 445 * @param
hudakz 0:ca476e0a1a28 446 * @retval
hudakz 0:ca476e0a1a28 447 */
hudakz 0:ca476e0a1a28 448 uint16_t RawEthernet::phyReadH(uint8_t address)
hudakz 0:ca476e0a1a28 449 {
hudakz 0:ca476e0a1a28 450 // set the right address and start the register read operation
hudakz 0:ca476e0a1a28 451 writeReg(MIREGADR, address);
hudakz 0:ca476e0a1a28 452 writeReg(MICMD, MICMD_MIIRD);
hudakz 0:ca476e0a1a28 453 wait_us(15);
hudakz 0:ca476e0a1a28 454
hudakz 0:ca476e0a1a28 455 // wait until the PHY read completes
hudakz 0:ca476e0a1a28 456 while (readReg(MISTAT) & MISTAT_BUSY);
hudakz 0:ca476e0a1a28 457
hudakz 0:ca476e0a1a28 458 // reset reading bit
hudakz 0:ca476e0a1a28 459 setBank(2);
hudakz 0:ca476e0a1a28 460 writeReg(MICMD, 0x00);
hudakz 0:ca476e0a1a28 461
hudakz 0:ca476e0a1a28 462 return(readReg(MIRDH));
hudakz 0:ca476e0a1a28 463 }
hudakz 0:ca476e0a1a28 464
hudakz 0:ca476e0a1a28 465 /**
hudakz 0:ca476e0a1a28 466 * @brief
hudakz 0:ca476e0a1a28 467 * @note
hudakz 0:ca476e0a1a28 468 * @param
hudakz 0:ca476e0a1a28 469 * @retval
hudakz 0:ca476e0a1a28 470 */
hudakz 0:ca476e0a1a28 471 void RawEthernet::phyWrite(uint8_t address, uint16_t data)
hudakz 0:ca476e0a1a28 472 {
hudakz 0:ca476e0a1a28 473 setBank(2);
hudakz 0:ca476e0a1a28 474
hudakz 0:ca476e0a1a28 475 // set the PHY register address
hudakz 0:ca476e0a1a28 476 writeReg(MIREGADR, address);
hudakz 0:ca476e0a1a28 477
hudakz 0:ca476e0a1a28 478 // write the PHY data
hudakz 0:ca476e0a1a28 479 writeReg(MIWRL, data);
hudakz 0:ca476e0a1a28 480 writeReg(MIWRH, data >> 8);
hudakz 0:ca476e0a1a28 481
hudakz 0:ca476e0a1a28 482 // wait until the PHY write completes
hudakz 0:ca476e0a1a28 483 setBank(3);
hudakz 0:ca476e0a1a28 484 while (readReg(MISTAT) & MISTAT_BUSY) {
hudakz 0:ca476e0a1a28 485 wait_us(15);
hudakz 0:ca476e0a1a28 486 }
hudakz 0:ca476e0a1a28 487 }
hudakz 0:ca476e0a1a28 488
hudakz 0:ca476e0a1a28 489 /**
hudakz 0:ca476e0a1a28 490 * @brief
hudakz 0:ca476e0a1a28 491 * @note
hudakz 0:ca476e0a1a28 492 * @param
hudakz 0:ca476e0a1a28 493 * @retval
hudakz 0:ca476e0a1a28 494 */
hudakz 0:ca476e0a1a28 495 void RawEthernet::linkTo(uint8_t remoteMac[6])
hudakz 0:ca476e0a1a28 496 {
hudakz 0:ca476e0a1a28 497 for (int i = 0; i < 6; i++)
hudakz 0:ca476e0a1a28 498 _remoteMac[i] = remoteMac[i];
hudakz 0:ca476e0a1a28 499
hudakz 0:ca476e0a1a28 500 _spi.format(8, 0); // 8bit, mode 0
hudakz 0:ca476e0a1a28 501 _spi.frequency(7000000); // 7MHz
hudakz 0:ca476e0a1a28 502 wait(1); // 1 second for stable state
hudakz 0:ca476e0a1a28 503 // initialize I/O
hudakz 0:ca476e0a1a28 504 _cs = 1;
hudakz 0:ca476e0a1a28 505 // perform system reset
hudakz 0:ca476e0a1a28 506 writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
hudakz 0:ca476e0a1a28 507 wait_ms(50);
hudakz 0:ca476e0a1a28 508 // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
hudakz 0:ca476e0a1a28 509 //while(!(read(ESTAT) & ESTAT_CLKRDY));
hudakz 0:ca476e0a1a28 510 // do bank 0 stuff
hudakz 0:ca476e0a1a28 511 // initialize receive buffer
hudakz 0:ca476e0a1a28 512 // 16-bit transfers, must write low byte first
hudakz 0:ca476e0a1a28 513 // set receive buffer start address
hudakz 0:ca476e0a1a28 514 _nextPacketPtr = RXSTART_INIT;
hudakz 0:ca476e0a1a28 515
hudakz 0:ca476e0a1a28 516 // Rx start
hudakz 0:ca476e0a1a28 517 writeReg(ERXSTL, RXSTART_INIT & 0xFF);
hudakz 0:ca476e0a1a28 518 writeReg(ERXSTH, RXSTART_INIT >> 8);
hudakz 0:ca476e0a1a28 519
hudakz 0:ca476e0a1a28 520 // set receive pointer address
hudakz 0:ca476e0a1a28 521 writeReg(ERXRDPTL, RXSTART_INIT & 0xFF);
hudakz 0:ca476e0a1a28 522 writeReg(ERXRDPTH, RXSTART_INIT >> 8);
hudakz 0:ca476e0a1a28 523
hudakz 0:ca476e0a1a28 524 // RX end
hudakz 0:ca476e0a1a28 525 writeReg(ERXNDL, RXSTOP_INIT & 0xFF);
hudakz 0:ca476e0a1a28 526 writeReg(ERXNDH, RXSTOP_INIT >> 8);
hudakz 0:ca476e0a1a28 527
hudakz 0:ca476e0a1a28 528 // TX start
hudakz 0:ca476e0a1a28 529 writeReg(ETXSTL, TXSTART_INIT & 0xFF);
hudakz 0:ca476e0a1a28 530 writeReg(ETXSTH, TXSTART_INIT >> 8);
hudakz 0:ca476e0a1a28 531
hudakz 0:ca476e0a1a28 532 // TX end (initialize for a packet with a payload of 1 byte)
hudakz 0:ca476e0a1a28 533 uint16_t address = (TXSTART_INIT + ETH_HEADER_LEN + 1);
hudakz 0:ca476e0a1a28 534 writeReg(ETXNDL, address & 0xFF);
hudakz 0:ca476e0a1a28 535 writeReg(ETXNDH, address >> 8);
hudakz 0:ca476e0a1a28 536
hudakz 0:ca476e0a1a28 537 // prepare the parts of the transmit packet that never change
hudakz 0:ca476e0a1a28 538 // write per-packet control byte (0x00 means use macon3 settings)
hudakz 0:ca476e0a1a28 539 writeReg(EWRPTL, (TXSTART_INIT) & 0xFF);
hudakz 0:ca476e0a1a28 540 writeReg(EWRPTH, (TXSTART_INIT) >> 8);
hudakz 0:ca476e0a1a28 541 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
hudakz 0:ca476e0a1a28 542
hudakz 0:ca476e0a1a28 543 // write broadcast address as DST MAC
hudakz 0:ca476e0a1a28 544 uint8_t i = 0;
hudakz 0:ca476e0a1a28 545 while (i < 6) {
hudakz 0:ca476e0a1a28 546 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xFF);
hudakz 0:ca476e0a1a28 547 i++;
hudakz 0:ca476e0a1a28 548 }
hudakz 0:ca476e0a1a28 549
hudakz 0:ca476e0a1a28 550 // set our MAC address as the SRC MAC into the transmit buffer
hudakz 0:ca476e0a1a28 551 // set the write pointer to start of transmit buffer area
hudakz 0:ca476e0a1a28 552 writeBuffer(6, const_cast<uint8_t*>(_mac));
hudakz 0:ca476e0a1a28 553 // First EtherType/length byte is always 0, initialize second byte to 1
hudakz 0:ca476e0a1a28 554 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
hudakz 0:ca476e0a1a28 555 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x01);
hudakz 0:ca476e0a1a28 556
hudakz 0:ca476e0a1a28 557 // do bank 1 stuff, packet filter:
hudakz 0:ca476e0a1a28 558 setBank(1);
hudakz 0:ca476e0a1a28 559 // only allow unicast packets destined for us and that have a correct CRC
hudakz 0:ca476e0a1a28 560 writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN);
hudakz 0:ca476e0a1a28 561
hudakz 0:ca476e0a1a28 562 // do bank 2 stuff
hudakz 0:ca476e0a1a28 563 setBank(2);
hudakz 0:ca476e0a1a28 564 // enable MAC receive, disable flow control (only needed in full-duplex)
hudakz 0:ca476e0a1a28 565 writeReg(MACON1, MACON1_MARXEN);
hudakz 0:ca476e0a1a28 566 // bring MAC out of reset
hudakz 0:ca476e0a1a28 567 writeReg(MACON2, 0x00);
hudakz 0:ca476e0a1a28 568 // enable automatic padding to 60bytes and CRC operations
hudakz 0:ca476e0a1a28 569 // also, force half-duplex operation
hudakz 0:ca476e0a1a28 570 writeReg(MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
hudakz 0:ca476e0a1a28 571 // half-duplex only: back-off settings
hudakz 0:ca476e0a1a28 572 writeReg(MACON4, MACON4_DEFER | MACON4_BPEN | MACON4_NOBKOFF);
hudakz 0:ca476e0a1a28 573 // set the maximum packet size which the controller will accept
hudakz 0:ca476e0a1a28 574 // do not send packets longer than MAX_FRAMELEN:
hudakz 0:ca476e0a1a28 575 writeReg(MAMXFLL, ENC28J60_MAX_PACKET_LEN & 0xFF);
hudakz 0:ca476e0a1a28 576 writeReg(MAMXFLH, ENC28J60_MAX_PACKET_LEN >> 8);
hudakz 0:ca476e0a1a28 577 // set inter-frame gap (non-back-to-back)
hudakz 0:ca476e0a1a28 578 writeReg(MAIPGL, 0x12);
hudakz 0:ca476e0a1a28 579 writeReg(MAIPGH, 0x0C);
hudakz 0:ca476e0a1a28 580 // set inter-frame gap (back-to-back)
hudakz 0:ca476e0a1a28 581 writeReg(MABBIPG, 0x12);
hudakz 0:ca476e0a1a28 582
hudakz 0:ca476e0a1a28 583 // do bank 3 stuff
hudakz 0:ca476e0a1a28 584 // write MAC address
hudakz 0:ca476e0a1a28 585 // NOTE: MAC address in ENC28J60 is byte-backward
hudakz 0:ca476e0a1a28 586 writeReg(MAADR5, _mac[0]);
hudakz 0:ca476e0a1a28 587 writeReg(MAADR4, _mac[1]);
hudakz 0:ca476e0a1a28 588 writeReg(MAADR3, _mac[2]);
hudakz 0:ca476e0a1a28 589 writeReg(MAADR2, _mac[3]);
hudakz 0:ca476e0a1a28 590 writeReg(MAADR1, _mac[4]);
hudakz 0:ca476e0a1a28 591 writeReg(MAADR0, _mac[5]);
hudakz 0:ca476e0a1a28 592
hudakz 0:ca476e0a1a28 593 // no loopback of transmitted frames
hudakz 0:ca476e0a1a28 594 phyWrite(PHCON2, PHCON2_HDLDIS);
hudakz 0:ca476e0a1a28 595
hudakz 0:ca476e0a1a28 596 // switch to bank 0
hudakz 0:ca476e0a1a28 597 setBank(ECON1);
hudakz 0:ca476e0a1a28 598
hudakz 0:ca476e0a1a28 599 // enable interrutps
hudakz 0:ca476e0a1a28 600 writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
hudakz 0:ca476e0a1a28 601
hudakz 0:ca476e0a1a28 602 // enable packet reception
hudakz 0:ca476e0a1a28 603 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
hudakz 0:ca476e0a1a28 604
hudakz 0:ca476e0a1a28 605 // change clkout from 6.25MHz to 12.5MHz
hudakz 0:ca476e0a1a28 606 writeReg(ECOCON, 2 & 0x7);
hudakz 0:ca476e0a1a28 607 wait_us(60);
hudakz 0:ca476e0a1a28 608
hudakz 0:ca476e0a1a28 609 /* magjack leds configuration, see enc28j60 datasheet, page 11 */
hudakz 0:ca476e0a1a28 610 // LEDA=green, LEDB=yellow,
hudakz 0:ca476e0a1a28 611 // LEDA=links status, LEDB=receive/transmit
hudakz 0:ca476e0a1a28 612 // phyWrite(PHLCON,0b0000 0100 0111 0110);
hudakz 0:ca476e0a1a28 613 phyWrite(PHLCON, 0x476);
hudakz 0:ca476e0a1a28 614
hudakz 0:ca476e0a1a28 615 // wait until the link is up, then send a gratuitous ARP request
hudakz 0:ca476e0a1a28 616 // to inform any conected switch about my existence
hudakz 0:ca476e0a1a28 617 while (!isLinkUp());
hudakz 0:ca476e0a1a28 618 wait_ms(50);
hudakz 0:ca476e0a1a28 619 // send gratuitous ARP request
hudakz 0:ca476e0a1a28 620 gratuitousArp();
hudakz 0:ca476e0a1a28 621 }
hudakz 0:ca476e0a1a28 622
hudakz 0:ca476e0a1a28 623 /**
hudakz 0:ca476e0a1a28 624 * @brief
hudakz 0:ca476e0a1a28 625 * @note
hudakz 0:ca476e0a1a28 626 * @param
hudakz 0:ca476e0a1a28 627 * @retval
hudakz 0:ca476e0a1a28 628 */
hudakz 0:ca476e0a1a28 629 bool RawEthernet::isLinkUp(void)
hudakz 0:ca476e0a1a28 630 {
hudakz 0:ca476e0a1a28 631 return(phyReadH(PHSTAT2) & PHSTAT2H_LSTAT);
hudakz 0:ca476e0a1a28 632 }
hudakz 0:ca476e0a1a28 633
hudakz 0:ca476e0a1a28 634 /**
hudakz 0:ca476e0a1a28 635 * @brief
hudakz 0:ca476e0a1a28 636 * @note
hudakz 0:ca476e0a1a28 637 * @param
hudakz 0:ca476e0a1a28 638 * @retval
hudakz 0:ca476e0a1a28 639 */
hudakz 0:ca476e0a1a28 640 uint8_t RawEthernet::receive(uint8_t* buf, uint8_t maxlen)
hudakz 0:ca476e0a1a28 641 {
hudakz 0:ca476e0a1a28 642 uint16_t len;
hudakz 0:ca476e0a1a28 643 uint16_t currentPacketPtr = _nextPacketPtr;
hudakz 0:ca476e0a1a28 644 uint16_t address;
hudakz 0:ca476e0a1a28 645 uint16_t framelen;
hudakz 0:ca476e0a1a28 646
hudakz 0:ca476e0a1a28 647 // check if a packet has been received and buffered
hudakz 0:ca476e0a1a28 648 setBank(1);
hudakz 0:ca476e0a1a28 649 if (readReg(EPKTCNT) == 0)
hudakz 0:ca476e0a1a28 650 return(0);
hudakz 0:ca476e0a1a28 651
hudakz 0:ca476e0a1a28 652 setBank(0);
hudakz 0:ca476e0a1a28 653
hudakz 0:ca476e0a1a28 654 // Somehow, the read pointer is NOT already at the start of the next packet
hudakz 0:ca476e0a1a28 655 // even though we leave it in that state
hudakz 0:ca476e0a1a28 656 writeReg(ERDPTL, (_nextPacketPtr & 0xff));
hudakz 0:ca476e0a1a28 657 writeReg(ERDPTH, (_nextPacketPtr) >> 8);
hudakz 0:ca476e0a1a28 658 // Read the next packet pointer
hudakz 0:ca476e0a1a28 659 _nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:ca476e0a1a28 660 _nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
hudakz 0:ca476e0a1a28 661 // read the frame length
hudakz 0:ca476e0a1a28 662 framelen = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:ca476e0a1a28 663 framelen |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
hudakz 0:ca476e0a1a28 664 if (maxlen > framelen - 14) {
hudakz 0:ca476e0a1a28 665 // subtract eth source, dest and length fields
hudakz 0:ca476e0a1a28 666 maxlen = framelen - 14;
hudakz 0:ca476e0a1a28 667 }
hudakz 0:ca476e0a1a28 668
hudakz 0:ca476e0a1a28 669 // Read EtherType (we use this as a length field) (note +6 for receive vectors)
hudakz 0:ca476e0a1a28 670 // Set read pointer (taking care of wrap-around)
hudakz 0:ca476e0a1a28 671 address = currentPacketPtr + ETH_TYPE_H_P + 6;
hudakz 0:ca476e0a1a28 672 if (address > RXSTOP_INIT) {
hudakz 0:ca476e0a1a28 673 address -= (RXSTOP_INIT - RXSTART_INIT + 1);
hudakz 0:ca476e0a1a28 674 }
hudakz 0:ca476e0a1a28 675
hudakz 0:ca476e0a1a28 676 writeReg(ERDPTL, (address & 0xff));
hudakz 0:ca476e0a1a28 677 writeReg(ERDPTH, (address) >> 8);
hudakz 0:ca476e0a1a28 678 readBuffer(6, _remoteMac);
hudakz 0:ca476e0a1a28 679
hudakz 0:ca476e0a1a28 680 // A value of less than 0x05dc in the EtherType has to be interpreted as length.
hudakz 0:ca476e0a1a28 681 // This is what we do here.
hudakz 0:ca476e0a1a28 682 // The length is 16 bit. The upper 8 bits must be zero
hudakz 0:ca476e0a1a28 683 // otherwise it is not our packet.
hudakz 0:ca476e0a1a28 684 len = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:ca476e0a1a28 685 if (len == 0) {
hudakz 0:ca476e0a1a28 686 // read the lower byte of the length field
hudakz 0:ca476e0a1a28 687 len = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:ca476e0a1a28 688 // limit retrieve length to maxlen, ignoring anything else
hudakz 0:ca476e0a1a28 689 if (len > maxlen) {
hudakz 0:ca476e0a1a28 690 len = maxlen;
hudakz 0:ca476e0a1a28 691 }
hudakz 0:ca476e0a1a28 692
hudakz 0:ca476e0a1a28 693 // copy payload data from the receive buffer
hudakz 0:ca476e0a1a28 694 readBuffer(len, buf);
hudakz 0:ca476e0a1a28 695 }
hudakz 0:ca476e0a1a28 696 else
hudakz 0:ca476e0a1a28 697 len = 0;
hudakz 0:ca476e0a1a28 698
hudakz 0:ca476e0a1a28 699 // Move the RX read pointer to the start of the next received packet
hudakz 0:ca476e0a1a28 700 // This frees the memory we just read out.
hudakz 0:ca476e0a1a28 701 // However, compensate for the errata point 13, rev B4: enver write an even address!
hudakz 0:ca476e0a1a28 702 if ((_nextPacketPtr - 1 < RXSTART_INIT) || (_nextPacketPtr - 1 > RXSTOP_INIT)) {
hudakz 0:ca476e0a1a28 703 writeReg(ERXRDPTL, (RXSTOP_INIT) & 0xFF);
hudakz 0:ca476e0a1a28 704 writeReg(ERXRDPTH, (RXSTOP_INIT) >> 8);
hudakz 0:ca476e0a1a28 705 }
hudakz 0:ca476e0a1a28 706 else {
hudakz 0:ca476e0a1a28 707 writeReg(ERXRDPTL, (_nextPacketPtr - 1) & 0xFF);
hudakz 0:ca476e0a1a28 708 writeReg(ERXRDPTH, (_nextPacketPtr - 1) >> 8);
hudakz 0:ca476e0a1a28 709 }
hudakz 0:ca476e0a1a28 710
hudakz 0:ca476e0a1a28 711 // Decrement the packet counter indicate we are done with this packet
hudakz 0:ca476e0a1a28 712 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
hudakz 0:ca476e0a1a28 713 return(len);
hudakz 0:ca476e0a1a28 714 }
hudakz 0:ca476e0a1a28 715
hudakz 0:ca476e0a1a28 716 // sends gratuitous ARP request (spontaneous arp request) to teach
hudakz 0:ca476e0a1a28 717
hudakz 0:ca476e0a1a28 718 // switches what our mac is.
hudakz 0:ca476e0a1a28 719 void RawEthernet::gratuitousArp()
hudakz 0:ca476e0a1a28 720 {
hudakz 0:ca476e0a1a28 721 uint8_t i = 0;
hudakz 0:ca476e0a1a28 722 uint16_t address;
hudakz 0:ca476e0a1a28 723 setBank(0);
hudakz 0:ca476e0a1a28 724
hudakz 0:ca476e0a1a28 725 // (control byte, and SRC MAC have already been set during init)
hudakz 0:ca476e0a1a28 726 #ifdef ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT
hudakz 0:ca476e0a1a28 727 // Check no transmit in progress
hudakz 0:ca476e0a1a28 728
hudakz 0:ca476e0a1a28 729 while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) {
hudakz 0:ca476e0a1a28 730 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
hudakz 0:ca476e0a1a28 731 if ((readReg(EIR) & EIR_TXERIF)) {
hudakz 0:ca476e0a1a28 732 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 733 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 734 }
hudakz 0:ca476e0a1a28 735 }
hudakz 0:ca476e0a1a28 736
hudakz 0:ca476e0a1a28 737 #else
hudakz 0:ca476e0a1a28 738 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
hudakz 0:ca476e0a1a28 739
hudakz 0:ca476e0a1a28 740 if ((readReg(EIR) & EIR_TXERIF)) {
hudakz 0:ca476e0a1a28 741 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 742 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 743 }
hudakz 0:ca476e0a1a28 744 #endif
hudakz 0:ca476e0a1a28 745 // Set the write pointer to start of transmit buffer area
hudakz 0:ca476e0a1a28 746
hudakz 0:ca476e0a1a28 747 // +1 to skip the per packet control byte and write directly the mac
hudakz 0:ca476e0a1a28 748 // The control byte was set to zero during initialisation and remains like that.
hudakz 0:ca476e0a1a28 749 writeReg(EWRPTL, (TXSTART_INIT + 1) & 0xFF);
hudakz 0:ca476e0a1a28 750 writeReg(EWRPTH, (TXSTART_INIT + 1) >> 8);
hudakz 0:ca476e0a1a28 751 // write a broadcase destination mac (all ff):
hudakz 0:ca476e0a1a28 752 while (i < 6) {
hudakz 0:ca476e0a1a28 753 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xFF);
hudakz 0:ca476e0a1a28 754 i++;
hudakz 0:ca476e0a1a28 755 }
hudakz 0:ca476e0a1a28 756
hudakz 0:ca476e0a1a28 757 // The mac in the ethernet field does not need to be changed.
hudakz 0:ca476e0a1a28 758 // Set the write pointer to the first byte of the EtherType field
hudakz 0:ca476e0a1a28 759 address = TXSTART_INIT + 1 + ETH_TYPE_H_P;
hudakz 0:ca476e0a1a28 760 writeReg(EWRPTL, address & 0xFF);
hudakz 0:ca476e0a1a28 761 writeReg(EWRPTH, address >> 8);
hudakz 0:ca476e0a1a28 762 // there are 10 fixed bytes in the arp request
hudakz 0:ca476e0a1a28 763 i = 0;
hudakz 0:ca476e0a1a28 764 while (i < 10) {
hudakz 0:ca476e0a1a28 765 writeOp(ENC28J60_WRITE_BUF_MEM, 0, (_arpReqHdr[i]));
hudakz 0:ca476e0a1a28 766 i++;
hudakz 0:ca476e0a1a28 767 }
hudakz 0:ca476e0a1a28 768
hudakz 0:ca476e0a1a28 769 i = 0;
hudakz 0:ca476e0a1a28 770 while (i < 6) {
hudakz 0:ca476e0a1a28 771 writeOp(ENC28J60_WRITE_BUF_MEM, 0, _mac[i]);
hudakz 0:ca476e0a1a28 772 i++;
hudakz 0:ca476e0a1a28 773 }
hudakz 0:ca476e0a1a28 774
hudakz 0:ca476e0a1a28 775 i = 0;
hudakz 0:ca476e0a1a28 776 while (i < 4) {
hudakz 0:ca476e0a1a28 777 writeOp(ENC28J60_WRITE_BUF_MEM, 0, _ip[i]);
hudakz 0:ca476e0a1a28 778 i++;
hudakz 0:ca476e0a1a28 779 }
hudakz 0:ca476e0a1a28 780
hudakz 0:ca476e0a1a28 781 // target data:
hudakz 0:ca476e0a1a28 782 i = 0;
hudakz 0:ca476e0a1a28 783 while (i < 6) {
hudakz 0:ca476e0a1a28 784 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xff);
hudakz 0:ca476e0a1a28 785 i++;
hudakz 0:ca476e0a1a28 786 }
hudakz 0:ca476e0a1a28 787
hudakz 0:ca476e0a1a28 788 // to self, for gratuitous arp:
hudakz 0:ca476e0a1a28 789 i = 0;
hudakz 0:ca476e0a1a28 790 while (i < 4) {
hudakz 0:ca476e0a1a28 791 writeOp(ENC28J60_WRITE_BUF_MEM, 0, _ip[i]);
hudakz 0:ca476e0a1a28 792 i++;
hudakz 0:ca476e0a1a28 793 }
hudakz 0:ca476e0a1a28 794
hudakz 0:ca476e0a1a28 795 // Set the TXND pointer to correspond to the payload size given
hudakz 0:ca476e0a1a28 796 address = (TXSTART_INIT + 42);
hudakz 0:ca476e0a1a28 797 writeReg(ETXNDL, address & 0xFF);
hudakz 0:ca476e0a1a28 798 writeReg(ETXNDH, address >> 8);
hudakz 0:ca476e0a1a28 799
hudakz 0:ca476e0a1a28 800 // Send the contents of the transmit buffer onto the network
hudakz 0:ca476e0a1a28 801 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
hudakz 0:ca476e0a1a28 802 }
hudakz 0:ca476e0a1a28 803
hudakz 0:ca476e0a1a28 804 /**
hudakz 0:ca476e0a1a28 805 * @brief
hudakz 0:ca476e0a1a28 806 * @note
hudakz 0:ca476e0a1a28 807 * @param
hudakz 0:ca476e0a1a28 808 * @retval
hudakz 0:ca476e0a1a28 809 */
hudakz 0:ca476e0a1a28 810 void RawEthernet::send(uint8_t* buf, uint8_t len)
hudakz 0:ca476e0a1a28 811 {
hudakz 0:ca476e0a1a28 812 uint16_t address;
hudakz 0:ca476e0a1a28 813 setBank(0);
hudakz 0:ca476e0a1a28 814
hudakz 0:ca476e0a1a28 815 // (control byte, and SRC MAC have already been set during init)
hudakz 0:ca476e0a1a28 816 #ifdef ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT
hudakz 0:ca476e0a1a28 817 // Check no transmit in progress
hudakz 0:ca476e0a1a28 818
hudakz 0:ca476e0a1a28 819 while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) {
hudakz 0:ca476e0a1a28 820 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
hudakz 0:ca476e0a1a28 821 if ((readReg(EIR) & EIR_TXERIF)) {
hudakz 0:ca476e0a1a28 822 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 823 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 824 }
hudakz 0:ca476e0a1a28 825 }
hudakz 0:ca476e0a1a28 826
hudakz 0:ca476e0a1a28 827 #else
hudakz 0:ca476e0a1a28 828 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
hudakz 0:ca476e0a1a28 829
hudakz 0:ca476e0a1a28 830 if ((readReg(EIR) & EIR_TXERIF)) {
hudakz 0:ca476e0a1a28 831 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 832 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
hudakz 0:ca476e0a1a28 833 }
hudakz 0:ca476e0a1a28 834 #endif
hudakz 0:ca476e0a1a28 835 // Set the write pointer to start of transmit buffer area
hudakz 0:ca476e0a1a28 836
hudakz 0:ca476e0a1a28 837 // +1 to skip the per packet control byte and write directly the mac
hudakz 0:ca476e0a1a28 838 // The control byte was set to zero during initialisation and remains like that.
hudakz 0:ca476e0a1a28 839 writeReg(EWRPTL, (TXSTART_INIT + 1) & 0xFF);
hudakz 0:ca476e0a1a28 840 writeReg(EWRPTH, (TXSTART_INIT + 1) >> 8);
hudakz 0:ca476e0a1a28 841 writeBuffer(6, _remoteMac);
hudakz 0:ca476e0a1a28 842
hudakz 0:ca476e0a1a28 843 // Set the write pointer to the first byte of the EtherType field
hudakz 0:ca476e0a1a28 844 // (field after the mac address). This is the 802.3 length field.
hudakz 0:ca476e0a1a28 845 address = TXSTART_INIT + 1 + ETH_TYPE_H_P;
hudakz 0:ca476e0a1a28 846 writeReg(EWRPTL, address & 0xFF);
hudakz 0:ca476e0a1a28 847 writeReg(EWRPTH, address >> 8);
hudakz 0:ca476e0a1a28 848 // write the length of the data in the ethernet type field.
hudakz 0:ca476e0a1a28 849 // The type field to be interpreted by the receiver as ieee802.3 length if
hudakz 0:ca476e0a1a28 850 // the value is less than 0x05dc (see e.g. http://www.cavebear.com/archive/cavebear/Ethernet/type.html ):
hudakz 0:ca476e0a1a28 851 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0);
hudakz 0:ca476e0a1a28 852 writeOp(ENC28J60_WRITE_BUF_MEM, 0, len);
hudakz 0:ca476e0a1a28 853 // Copy the payload into the transmit buffer
hudakz 0:ca476e0a1a28 854 writeBuffer(len, buf); // remove dest mac and write the rest
hudakz 0:ca476e0a1a28 855 // Set the TXND pointer to correspond to the payload size given
hudakz 0:ca476e0a1a28 856 address = (TXSTART_INIT + ETH_HEADER_LEN + len);
hudakz 0:ca476e0a1a28 857 writeReg(ETXNDL, address & 0xFF);
hudakz 0:ca476e0a1a28 858 writeReg(ETXNDH, address >> 8);
hudakz 0:ca476e0a1a28 859
hudakz 0:ca476e0a1a28 860 // Send the contents of the transmit buffer onto the network
hudakz 0:ca476e0a1a28 861 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
hudakz 0:ca476e0a1a28 862 }
hudakz 0:ca476e0a1a28 863
hudakz 0:ca476e0a1a28 864 /**
hudakz 0:ca476e0a1a28 865 * @brief
hudakz 0:ca476e0a1a28 866 * @note
hudakz 0:ca476e0a1a28 867 * @param
hudakz 0:ca476e0a1a28 868 * @retval
hudakz 0:ca476e0a1a28 869 */
hudakz 0:ca476e0a1a28 870 uint8_t RawEthernet::getRev(void)
hudakz 0:ca476e0a1a28 871 {
hudakz 0:ca476e0a1a28 872 uint8_t rev;
hudakz 0:ca476e0a1a28 873
hudakz 0:ca476e0a1a28 874 rev = readReg(EREVID);
hudakz 0:ca476e0a1a28 875
hudakz 0:ca476e0a1a28 876 // microchip forgott to step the number on the silcon when they
hudakz 0:ca476e0a1a28 877 // released the revision B7. 6 is now rev B7. We still have
hudakz 0:ca476e0a1a28 878 // to see what they do when they release B8. At the moment
hudakz 0:ca476e0a1a28 879 // there is no B8 out yet
hudakz 0:ca476e0a1a28 880 if (rev > 5)
hudakz 0:ca476e0a1a28 881 rev++;
hudakz 0:ca476e0a1a28 882 return(rev);
hudakz 0:ca476e0a1a28 883 }
hudakz 0:ca476e0a1a28 884