Enables fast realtime communication over Ethernet by using plain Ethernet frames (overhead of TCP/IP network layers is stripped away).
RawEthernet.cpp@0:ca476e0a1a28, 2018-08-20 (annotated)
- Committer:
- hudakz
- Date:
- Mon Aug 20 11:37:35 2018 +0000
- Revision:
- 0:ca476e0a1a28
Initial release.
Who changed what in which revision?
| User | Revision | Line number | New 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 |