Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
RawEthernet.cpp
00001 //------------------------------------------------------------------------------ 00002 // Functions for using an ENC28J60 ethernet controller, optimized for 00003 // communication speed. 00004 // 00005 // Written by Rogier Schouten http://www.rogiershikes.tk 00006 // Based on code by Guido Socher http://www.tuxgraphics.org 00007 // Idea modified and further updated by Guido Socher 00008 // Ported to MBED by Zoltan Hudak hudakz@outlook.com 00009 // License: GPL V2 00010 // 00011 // Enables to read sensor data or control IO-ports with less than a millisecond delay. 00012 // The trick is in removing the TCP/IP overhead and use raw Ethernet frames. 00013 // A Linux application using raw network sockets is controlling this slave device. 00014 // 00015 // Assumptions: 00016 // - Max. payload data: 255 bytes per packet 00017 // - The network consists of a master PC and one or more slave devices. 00018 // Only plain hubs and switches are allowed between PC and ethernet device. 00019 // Note that some wlan routers have internal switches which switch only 00020 // IP packets. They will discard plain ethernet frames. A normal 100Mbit 00021 // office/workgroup switch will however work. 00022 // 00023 // Based on these assumptions, we can optimize the protocol for faster communication: 00024 // - Master and slave send unicast packets. 00025 // - We use raw ethernet and no higher-level protocol such as UDP or TCP/IP 00026 // - We use the EtherType field of a packet as a length field. Actually, we only 00027 // use one byte of it since we have max 255 length packets. 00028 // 00029 // Furthermore, there are a few code optimizations: 00030 // - Minimize communication between ENC and MCU. 00031 // - No unnecessary memory bank checks 00032 // 00033 #include "RawEthernet.h" 00034 00035 // ENC28J60 Control Registers 00036 00037 // Control register definitions are a combination of address, 00038 // bank number, and Ethernet/MAC/PHY indicator bits. 00039 // - Register address (bits 0-4) 00040 // - Bank number (bits 5-6) 00041 // - MAC/PHY indicator (bit 7) 00042 #define ADDR_MASK 0x1F 00043 #define BANK_MASK 0x60 00044 #define SPRD_MASK 0x80 00045 // All-bank registers 00046 #define EIE 0x1B 00047 #define EIR 0x1C 00048 #define ESTAT 0x1D 00049 #define ECON2 0x1E 00050 #define ECON1 0x1F 00051 // Bank 0 registers 00052 #define ERDPTL (0x00 | 0x00) 00053 #define ERDPTH (0x01 | 0x00) 00054 #define EWRPTL (0x02 | 0x00) 00055 #define EWRPTH (0x03 | 0x00) 00056 #define ETXSTL (0x04 | 0x00) 00057 #define ETXSTH (0x05 | 0x00) 00058 #define ETXNDL (0x06 | 0x00) 00059 #define ETXNDH (0x07 | 0x00) 00060 #define ERXSTL (0x08 | 0x00) 00061 #define ERXSTH (0x09 | 0x00) 00062 #define ERXNDL (0x0A | 0x00) 00063 #define ERXNDH (0x0B | 0x00) 00064 #define ERXRDPTL (0x0C | 0x00) 00065 #define ERXRDPTH (0x0D | 0x00) 00066 #define ERXWRPTL (0x0E | 0x00) 00067 #define ERXWRPTH (0x0F | 0x00) 00068 #define EDMASTL (0x10 | 0x00) 00069 #define EDMASTH (0x11 | 0x00) 00070 #define EDMANDL (0x12 | 0x00) 00071 #define EDMANDH (0x13 | 0x00) 00072 #define EDMADSTL (0x14 | 0x00) 00073 #define EDMADSTH (0x15 | 0x00) 00074 #define EDMACSL (0x16 | 0x00) 00075 #define EDMACSH (0x17 | 0x00) 00076 // Bank 1 registers 00077 #define EHT0 (0x00 | 0x20) 00078 #define EHT1 (0x01 | 0x20) 00079 #define EHT2 (0x02 | 0x20) 00080 #define EHT3 (0x03 | 0x20) 00081 #define EHT4 (0x04 | 0x20) 00082 #define EHT5 (0x05 | 0x20) 00083 #define EHT6 (0x06 | 0x20) 00084 #define EHT7 (0x07 | 0x20) 00085 #define EPMM0 (0x08 | 0x20) 00086 #define EPMM1 (0x09 | 0x20) 00087 #define EPMM2 (0x0A | 0x20) 00088 #define EPMM3 (0x0B | 0x20) 00089 #define EPMM4 (0x0C | 0x20) 00090 #define EPMM5 (0x0D | 0x20) 00091 #define EPMM6 (0x0E | 0x20) 00092 #define EPMM7 (0x0F | 0x20) 00093 #define EPMCSL (0x10 | 0x20) 00094 #define EPMCSH (0x11 | 0x20) 00095 #define EPMOL (0x14 | 0x20) 00096 #define EPMOH (0x15 | 0x20) 00097 #define EWOLIE (0x16 | 0x20) 00098 #define EWOLIR (0x17 | 0x20) 00099 #define ERXFCON (0x18 | 0x20) 00100 #define EPKTCNT (0x19 | 0x20) 00101 // Bank 2 registers 00102 #define MACON1 (0x00 | 0x40 | 0x80) 00103 #define MACON2 (0x01 | 0x40 | 0x80) 00104 #define MACON3 (0x02 | 0x40 | 0x80) 00105 #define MACON4 (0x03 | 0x40 | 0x80) 00106 #define MABBIPG (0x04 | 0x40 | 0x80) 00107 #define MAIPGL (0x06 | 0x40 | 0x80) 00108 #define MAIPGH (0x07 | 0x40 | 0x80) 00109 #define MACLCON1 (0x08 | 0x40 | 0x80) 00110 #define MACLCON2 (0x09 | 0x40 | 0x80) 00111 #define MAMXFLL (0x0A | 0x40 | 0x80) 00112 #define MAMXFLH (0x0B | 0x40 | 0x80) 00113 #define MAPHSUP (0x0D | 0x40 | 0x80) 00114 #define MICON (0x11 | 0x40 | 0x80) 00115 #define MICMD (0x12 | 0x40 | 0x80) 00116 #define MIREGADR (0x14 | 0x40 | 0x80) 00117 #define MIWRL (0x16 | 0x40 | 0x80) 00118 #define MIWRH (0x17 | 0x40 | 0x80) 00119 #define MIRDL (0x18 | 0x40 | 0x80) 00120 #define MIRDH (0x19 | 0x40 | 0x80) 00121 // Bank 3 registers 00122 #define MAADR1 (0x00 | 0x60 | 0x80) 00123 #define MAADR0 (0x01 | 0x60 | 0x80) 00124 #define MAADR3 (0x02 | 0x60 | 0x80) 00125 #define MAADR2 (0x03 | 0x60 | 0x80) 00126 #define MAADR5 (0x04 | 0x60 | 0x80) 00127 #define MAADR4 (0x05 | 0x60 | 0x80) 00128 #define EBSTSD (0x06 | 0x60) 00129 #define EBSTCON (0x07 | 0x60) 00130 #define EBSTCSL (0x08 | 0x60) 00131 #define EBSTCSH (0x09 | 0x60) 00132 #define MISTAT (0x0A | 0x60 | 0x80) 00133 #define EREVID (0x12 | 0x60) 00134 #define ECOCON (0x15 | 0x60) 00135 #define EFLOCON (0x17 | 0x60) 00136 #define EPAUSL (0x18 | 0x60) 00137 #define EPAUSH (0x19 | 0x60) 00138 // PHY registers 00139 #define PHCON1 0x00 00140 #define PHSTAT1 0x01 00141 #define PHHID1 0x02 00142 #define PHHID2 0x03 00143 #define PHCON2 0x10 00144 #define PHSTAT2 0x11 00145 #define PHIE 0x12 00146 #define PHIR 0x13 00147 #define PHLCON 0x14 00148 // ENC28J60 ERXFCON Register Bit Definitions 00149 #define ERXFCON_UCEN 0x80 00150 #define ERXFCON_ANDOR 0x40 00151 #define ERXFCON_CRCEN 0x20 00152 #define ERXFCON_PMEN 0x10 00153 #define ERXFCON_MPEN 0x08 00154 #define ERXFCON_HTEN 0x04 00155 #define ERXFCON_MCEN 0x02 00156 #define ERXFCON_BCEN 0x01 00157 // ENC28J60 EIE Register Bit Definitions 00158 #define EIE_INTIE 0x80 00159 #define EIE_PKTIE 0x40 00160 #define EIE_DMAIE 0x20 00161 #define EIE_LINKIE 0x10 00162 #define EIE_TXIE 0x08 00163 #define EIE_WOLIE 0x04 00164 #define EIE_TXERIE 0x02 00165 #define EIE_RXERIE 0x01 00166 // ENC28J60 EIR Register Bit Definitions 00167 #define EIR_PKTIF 0x40 00168 #define EIR_DMAIF 0x20 00169 #define EIR_LINKIF 0x10 00170 #define EIR_TXIF 0x08 00171 #define EIR_WOLIF 0x04 00172 #define EIR_TXERIF 0x02 00173 #define EIR_RXERIF 0x01 00174 // ENC28J60 ESTAT Register Bit Definitions 00175 #define ESTAT_INT 0x80 00176 #define ESTAT_LATECOL 0x10 00177 #define ESTAT_RXBUSY 0x04 00178 #define ESTAT_TXABRT 0x02 00179 #define ESTAT_CLKRDY 0x01 00180 // ENC28J60 ECON2 Register Bit Definitions 00181 #define ECON2_AUTOINC 0x80 00182 #define ECON2_PKTDEC 0x40 00183 #define ECON2_PWRSV 0x20 00184 #define ECON2_VRPS 0x08 00185 // ENC28J60 ECON1 Register Bit Definitions 00186 #define ECON1_TXRST 0x80 00187 #define ECON1_RXRST 0x40 00188 #define ECON1_DMAST 0x20 00189 #define ECON1_CSUMEN 0x10 00190 #define ECON1_TXRTS 0x08 00191 #define ECON1_RXEN 0x04 00192 #define ECON1_BSEL1 0x02 00193 #define ECON1_BSEL0 0x01 00194 // ENC28J60 MACON1 Register Bit Definitions 00195 #define MACON1_LOOPBK 0x10 00196 #define MACON1_TXPAUS 0x08 00197 #define MACON1_RXPAUS 0x04 00198 #define MACON1_PASSALL 0x02 00199 #define MACON1_MARXEN 0x01 00200 // ENC28J60 MACON2 Register Bit Definitions 00201 #define MACON2_MARST 0x80 00202 #define MACON2_RNDRST 0x40 00203 #define MACON2_MARXRST 0x08 00204 #define MACON2_RFUNRST 0x04 00205 #define MACON2_MATXRST 0x02 00206 #define MACON2_TFUNRST 0x01 00207 // ENC28J60 MACON3 Register Bit Definitions 00208 #define MACON3_PADCFG2 0x80 00209 #define MACON3_PADCFG1 0x40 00210 #define MACON3_PADCFG0 0x20 00211 #define MACON3_TXCRCEN 0x10 00212 #define MACON3_PHDRLEN 0x08 00213 #define MACON3_HFRMLEN 0x04 00214 #define MACON3_FRMLNEN 0x02 00215 #define MACON3_FULDPX 0x01 00216 // ENC28J60 MACON4 Register Bit Definitions 00217 #define MACON4_DEFER 0x40 00218 #define MACON4_BPEN 0x20 00219 #define MACON4_NOBKOFF 0x10 00220 // ENC28J60 MICMD Register Bit Definitions 00221 #define MICMD_MIISCAN 0x02 00222 #define MICMD_MIIRD 0x01 00223 // ENC28J60 MISTAT Register Bit Definitions 00224 #define MISTAT_NVALID 0x04 00225 #define MISTAT_SCAN 0x02 00226 #define MISTAT_BUSY 0x01 00227 // ENC28J60 PHY PHCON1 Register Bit Definitions 00228 #define PHCON1_PRST 0x8000 00229 #define PHCON1_PLOOPBK 0x4000 00230 #define PHCON1_PPWRSV 0x0800 00231 #define PHCON1_PDPXMD 0x0100 00232 // ENC28J60 PHY PHSTAT1 Register Bit Definitions 00233 #define PHSTAT1_PFDPX 0x1000 00234 #define PHSTAT1_PHDPX 0x0800 00235 #define PHSTAT1_LLSTAT 0x0004 00236 #define PHSTAT1_JBSTAT 0x0002 00237 // ENC28J60 PHY PHSTAT2H Register Bit Definitions 00238 #define PHSTAT2H_LSTAT 0x04 00239 // ENC28J60 PHY PHCON2 Register Bit Definitions 00240 #define PHCON2_FRCLINK 0x4000 00241 #define PHCON2_TXDIS 0x2000 00242 #define PHCON2_JABBER 0x0400 00243 #define PHCON2_HDLDIS 0x0100 00244 // ENC28J60 Packet Control Byte Bit Definitions 00245 #define PKTCTRL_PHUGEEN 0x08 00246 #define PKTCTRL_PPADEN 0x04 00247 #define PKTCTRL_PCRCEN 0x02 00248 #define PKTCTRL_POVERRIDE 0x01 00249 // SPI operation codes 00250 #define ENC28J60_READ_CTRL_REG 0x00 00251 #define ENC28J60_READ_BUF_MEM 0x3A 00252 #define ENC28J60_WRITE_CTRL_REG 0x40 00253 #define ENC28J60_WRITE_BUF_MEM 0x7A 00254 #define ENC28J60_BIT_FIELD_SET 0x80 00255 #define ENC28J60_BIT_FIELD_CLR 0xA0 00256 #define ENC28J60_SOFT_RESET 0xFF 00257 // Buffer memory allocation within controlller. 00258 // Assuming the controller is slower than the network, we allocate one transmit 00259 // packet and leave the rest for receiving. 00260 // The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata 00261 #define RXSTART_INIT 0x0 00262 #define RXSTOP_INIT (0x1FFF - 0x0600 - 2) // note: MUST be odd (see errata point 13) 00263 #define TXSTART_INIT (0x1FFF - 0x0600) 00264 // Maximum packet length: this software has a limit of 255 payload data bytes 00265 // and then there is some ethernet overhead (srd, dst, len, fcs) 00266 #define ENC28J60_MAX_PACKET_LEN ((uint16_t) 273) 00267 // field or packet lengths 00268 #define ETH_HEADER_LEN 14 00269 #define ETH_CHECKSUM_LEN 4 00270 #define ETH_ENVELOPE_LEN (ETH_HEADER_LEN + ETH_CHECKSUM_LEN) 00271 #define ETH_PAYLOAD_MIN 46 00272 #define ETH_PAYLOAD_MAX 1500 00273 #define ETH_PACKET_MIN 64 00274 #define ETH_PACKET_MAX 1518 00275 // field locations in ethernet packet 00276 #define ETH_DST_MAC_P 0 00277 #define ETH_SRC_MAC_P 6 00278 #define ETH_TYPE_H_P 12 00279 #define ETH_TYPE_L_P 13 00280 #define ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT 00281 00282 /* Static member initialization */ 00283 char RawEthernet::_arpReqHdr[10] = { 8, 6, 0, 1, 8, 0, 6, 4, 0, 1 }; 00284 00285 /** 00286 * @brief Constructor 00287 * @note 00288 * @param mosi SPI master-out slave-in pin # 00289 * @param miso SPI master-in slave-out pin # 00290 * @param sclk SPI serial clock pin # 00291 * @param cs SPI chip select pin # 00292 * @retval 00293 */ 00294 RawEthernet::RawEthernet(PinName mosi, PinName miso, PinName sclk, PinName cs, uint8_t myMac[6], uint8_t myIp[4]) : 00295 _spi(mosi, miso, sclk), 00296 _cs(cs) 00297 { 00298 int i; 00299 00300 for (i = 0; i < 6; i++) 00301 _mac[i] = myMac[i]; 00302 00303 for (i = 0; i < 4; i++) 00304 _ip[i] = myIp[i]; 00305 } 00306 00307 /** 00308 * @brief Read operation 00309 * @note Reads from ENC28J60 register 00310 * @param op operation code 00311 * @param address register address 00312 * @retval Register value 00313 */ 00314 uint8_t RawEthernet::readOp(uint8_t op, uint8_t address) 00315 { 00316 uint8_t result; 00317 00318 _cs = 0; 00319 00320 // issue read command 00321 _spi.write(op | (address & ADDR_MASK)); 00322 00323 // read data 00324 result = _spi.write(0x00); 00325 00326 // do dummy read if needed (for mac and mii, see datasheet page 29) 00327 if (address & 0x80) 00328 result = _spi.write(0x00); 00329 00330 // release CS 00331 _cs = 1; 00332 return(result); 00333 } 00334 00335 /** 00336 * @brief Write operation 00337 * @note Writes to ENC28J60 register 00338 * @param op operation code 00339 * @param address register address 00340 * @retval data data to be written 00341 */ 00342 void RawEthernet::writeOp(uint8_t op, uint8_t address, uint8_t data) 00343 { 00344 _cs = 0; 00345 00346 // issue write command 00347 _spi.write(op | (address & ADDR_MASK)); 00348 00349 // write data 00350 _spi.write(data); 00351 _cs = 1; 00352 } 00353 00354 /** 00355 * @brief 00356 * @note 00357 * @param 00358 * @retval 00359 */ 00360 void RawEthernet::setBank(uint8_t address) 00361 { 00362 // set the bank (if needed) 00363 if ((address & BANK_MASK) != _bank) { 00364 // set the bank 00365 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0)); 00366 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5); 00367 _bank = (address & BANK_MASK); 00368 } 00369 } 00370 00371 /** 00372 * @brief 00373 * @note 00374 * @param 00375 * @retval 00376 */ 00377 uint8_t RawEthernet::readReg(uint8_t address) 00378 { 00379 setBank(address); 00380 readOp(ENC28J60_READ_CTRL_REG, address); 00381 } 00382 00383 /** 00384 * @brief 00385 * @note 00386 * @param 00387 * @retval 00388 */ 00389 void RawEthernet::writeReg(uint8_t address, uint8_t data) 00390 { 00391 setBank(address); 00392 writeOp(ENC28J60_WRITE_CTRL_REG, address, data); 00393 } 00394 00395 /** 00396 * @brief 00397 * @note 00398 * @param 00399 * @retval 00400 */ 00401 void RawEthernet::readBuffer(uint16_t len, uint8_t* data) 00402 { 00403 _cs = 0; 00404 00405 // issue read command 00406 _spi.write(ENC28J60_READ_BUF_MEM); 00407 while (len) { 00408 len--; 00409 00410 // read data 00411 *data = _spi.write(0x00); 00412 data++; 00413 } 00414 00415 //*data = '\0'; 00416 _cs = 1; 00417 } 00418 00419 /** 00420 * @brief 00421 * @note 00422 * @param 00423 * @retval 00424 */ 00425 void RawEthernet::writeBuffer(uint16_t len, uint8_t* data) 00426 { 00427 _cs = 0; 00428 00429 // issue write command 00430 _spi.write(ENC28J60_WRITE_BUF_MEM); 00431 while (len) { 00432 len--; 00433 00434 // write data 00435 _spi.write(*data); 00436 data++; 00437 } 00438 00439 _cs = 1; 00440 } 00441 00442 /** 00443 * @brief 00444 * @note 00445 * @param 00446 * @retval 00447 */ 00448 uint16_t RawEthernet::phyReadH(uint8_t address) 00449 { 00450 // set the right address and start the register read operation 00451 writeReg(MIREGADR, address); 00452 writeReg(MICMD, MICMD_MIIRD); 00453 wait_us(15); 00454 00455 // wait until the PHY read completes 00456 while (readReg(MISTAT) & MISTAT_BUSY); 00457 00458 // reset reading bit 00459 setBank(2); 00460 writeReg(MICMD, 0x00); 00461 00462 return(readReg(MIRDH)); 00463 } 00464 00465 /** 00466 * @brief 00467 * @note 00468 * @param 00469 * @retval 00470 */ 00471 void RawEthernet::phyWrite(uint8_t address, uint16_t data) 00472 { 00473 setBank(2); 00474 00475 // set the PHY register address 00476 writeReg(MIREGADR, address); 00477 00478 // write the PHY data 00479 writeReg(MIWRL, data); 00480 writeReg(MIWRH, data >> 8); 00481 00482 // wait until the PHY write completes 00483 setBank(3); 00484 while (readReg(MISTAT) & MISTAT_BUSY) { 00485 wait_us(15); 00486 } 00487 } 00488 00489 /** 00490 * @brief 00491 * @note 00492 * @param 00493 * @retval 00494 */ 00495 void RawEthernet::linkTo(uint8_t remoteMac[6]) 00496 { 00497 for (int i = 0; i < 6; i++) 00498 _remoteMac[i] = remoteMac[i]; 00499 00500 _spi.format(8, 0); // 8bit, mode 0 00501 _spi.frequency(7000000); // 7MHz 00502 wait(1); // 1 second for stable state 00503 // initialize I/O 00504 _cs = 1; 00505 // perform system reset 00506 writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); 00507 wait_ms(50); 00508 // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait. 00509 //while(!(read(ESTAT) & ESTAT_CLKRDY)); 00510 // do bank 0 stuff 00511 // initialize receive buffer 00512 // 16-bit transfers, must write low byte first 00513 // set receive buffer start address 00514 _nextPacketPtr = RXSTART_INIT; 00515 00516 // Rx start 00517 writeReg(ERXSTL, RXSTART_INIT & 0xFF); 00518 writeReg(ERXSTH, RXSTART_INIT >> 8); 00519 00520 // set receive pointer address 00521 writeReg(ERXRDPTL, RXSTART_INIT & 0xFF); 00522 writeReg(ERXRDPTH, RXSTART_INIT >> 8); 00523 00524 // RX end 00525 writeReg(ERXNDL, RXSTOP_INIT & 0xFF); 00526 writeReg(ERXNDH, RXSTOP_INIT >> 8); 00527 00528 // TX start 00529 writeReg(ETXSTL, TXSTART_INIT & 0xFF); 00530 writeReg(ETXSTH, TXSTART_INIT >> 8); 00531 00532 // TX end (initialize for a packet with a payload of 1 byte) 00533 uint16_t address = (TXSTART_INIT + ETH_HEADER_LEN + 1); 00534 writeReg(ETXNDL, address & 0xFF); 00535 writeReg(ETXNDH, address >> 8); 00536 00537 // prepare the parts of the transmit packet that never change 00538 // write per-packet control byte (0x00 means use macon3 settings) 00539 writeReg(EWRPTL, (TXSTART_INIT) & 0xFF); 00540 writeReg(EWRPTH, (TXSTART_INIT) >> 8); 00541 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00); 00542 00543 // write broadcast address as DST MAC 00544 uint8_t i = 0; 00545 while (i < 6) { 00546 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xFF); 00547 i++; 00548 } 00549 00550 // set our MAC address as the SRC MAC into the transmit buffer 00551 // set the write pointer to start of transmit buffer area 00552 writeBuffer(6, const_cast<uint8_t*>(_mac)); 00553 // First EtherType/length byte is always 0, initialize second byte to 1 00554 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00); 00555 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x01); 00556 00557 // do bank 1 stuff, packet filter: 00558 setBank(1); 00559 // only allow unicast packets destined for us and that have a correct CRC 00560 writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN); 00561 00562 // do bank 2 stuff 00563 setBank(2); 00564 // enable MAC receive, disable flow control (only needed in full-duplex) 00565 writeReg(MACON1, MACON1_MARXEN); 00566 // bring MAC out of reset 00567 writeReg(MACON2, 0x00); 00568 // enable automatic padding to 60bytes and CRC operations 00569 // also, force half-duplex operation 00570 writeReg(MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); 00571 // half-duplex only: back-off settings 00572 writeReg(MACON4, MACON4_DEFER | MACON4_BPEN | MACON4_NOBKOFF); 00573 // set the maximum packet size which the controller will accept 00574 // do not send packets longer than MAX_FRAMELEN: 00575 writeReg(MAMXFLL, ENC28J60_MAX_PACKET_LEN & 0xFF); 00576 writeReg(MAMXFLH, ENC28J60_MAX_PACKET_LEN >> 8); 00577 // set inter-frame gap (non-back-to-back) 00578 writeReg(MAIPGL, 0x12); 00579 writeReg(MAIPGH, 0x0C); 00580 // set inter-frame gap (back-to-back) 00581 writeReg(MABBIPG, 0x12); 00582 00583 // do bank 3 stuff 00584 // write MAC address 00585 // NOTE: MAC address in ENC28J60 is byte-backward 00586 writeReg(MAADR5, _mac[0]); 00587 writeReg(MAADR4, _mac[1]); 00588 writeReg(MAADR3, _mac[2]); 00589 writeReg(MAADR2, _mac[3]); 00590 writeReg(MAADR1, _mac[4]); 00591 writeReg(MAADR0, _mac[5]); 00592 00593 // no loopback of transmitted frames 00594 phyWrite(PHCON2, PHCON2_HDLDIS); 00595 00596 // switch to bank 0 00597 setBank(ECON1); 00598 00599 // enable interrutps 00600 writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE); 00601 00602 // enable packet reception 00603 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); 00604 00605 // change clkout from 6.25MHz to 12.5MHz 00606 writeReg(ECOCON, 2 & 0x7); 00607 wait_us(60); 00608 00609 /* magjack leds configuration, see enc28j60 datasheet, page 11 */ 00610 // LEDA=green, LEDB=yellow, 00611 // LEDA=links status, LEDB=receive/transmit 00612 // phyWrite(PHLCON,0b0000 0100 0111 0110); 00613 phyWrite(PHLCON, 0x476); 00614 00615 // wait until the link is up, then send a gratuitous ARP request 00616 // to inform any conected switch about my existence 00617 while (!isLinkUp()); 00618 wait_ms(50); 00619 // send gratuitous ARP request 00620 gratuitousArp(); 00621 } 00622 00623 /** 00624 * @brief 00625 * @note 00626 * @param 00627 * @retval 00628 */ 00629 bool RawEthernet::isLinkUp(void) 00630 { 00631 return(phyReadH(PHSTAT2) & PHSTAT2H_LSTAT); 00632 } 00633 00634 /** 00635 * @brief 00636 * @note 00637 * @param 00638 * @retval 00639 */ 00640 uint8_t RawEthernet::receive(uint8_t* buf, uint8_t maxlen) 00641 { 00642 uint16_t len; 00643 uint16_t currentPacketPtr = _nextPacketPtr; 00644 uint16_t address; 00645 uint16_t framelen; 00646 00647 // check if a packet has been received and buffered 00648 setBank(1); 00649 if (readReg(EPKTCNT) == 0) 00650 return(0); 00651 00652 setBank(0); 00653 00654 // Somehow, the read pointer is NOT already at the start of the next packet 00655 // even though we leave it in that state 00656 writeReg(ERDPTL, (_nextPacketPtr & 0xff)); 00657 writeReg(ERDPTH, (_nextPacketPtr) >> 8); 00658 // Read the next packet pointer 00659 _nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); 00660 _nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; 00661 // read the frame length 00662 framelen = readOp(ENC28J60_READ_BUF_MEM, 0); 00663 framelen |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; 00664 if (maxlen > framelen - 14) { 00665 // subtract eth source, dest and length fields 00666 maxlen = framelen - 14; 00667 } 00668 00669 // Read EtherType (we use this as a length field) (note +6 for receive vectors) 00670 // Set read pointer (taking care of wrap-around) 00671 address = currentPacketPtr + ETH_TYPE_H_P + 6; 00672 if (address > RXSTOP_INIT) { 00673 address -= (RXSTOP_INIT - RXSTART_INIT + 1); 00674 } 00675 00676 writeReg(ERDPTL, (address & 0xff)); 00677 writeReg(ERDPTH, (address) >> 8); 00678 readBuffer(6, _remoteMac); 00679 00680 // A value of less than 0x05dc in the EtherType has to be interpreted as length. 00681 // This is what we do here. 00682 // The length is 16 bit. The upper 8 bits must be zero 00683 // otherwise it is not our packet. 00684 len = readOp(ENC28J60_READ_BUF_MEM, 0); 00685 if (len == 0) { 00686 // read the lower byte of the length field 00687 len = readOp(ENC28J60_READ_BUF_MEM, 0); 00688 // limit retrieve length to maxlen, ignoring anything else 00689 if (len > maxlen) { 00690 len = maxlen; 00691 } 00692 00693 // copy payload data from the receive buffer 00694 readBuffer(len, buf); 00695 } 00696 else 00697 len = 0; 00698 00699 // Move the RX read pointer to the start of the next received packet 00700 // This frees the memory we just read out. 00701 // However, compensate for the errata point 13, rev B4: enver write an even address! 00702 if ((_nextPacketPtr - 1 < RXSTART_INIT) || (_nextPacketPtr - 1 > RXSTOP_INIT)) { 00703 writeReg(ERXRDPTL, (RXSTOP_INIT) & 0xFF); 00704 writeReg(ERXRDPTH, (RXSTOP_INIT) >> 8); 00705 } 00706 else { 00707 writeReg(ERXRDPTL, (_nextPacketPtr - 1) & 0xFF); 00708 writeReg(ERXRDPTH, (_nextPacketPtr - 1) >> 8); 00709 } 00710 00711 // Decrement the packet counter indicate we are done with this packet 00712 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); 00713 return(len); 00714 } 00715 00716 // sends gratuitous ARP request (spontaneous arp request) to teach 00717 00718 // switches what our mac is. 00719 void RawEthernet::gratuitousArp() 00720 { 00721 uint8_t i = 0; 00722 uint16_t address; 00723 setBank(0); 00724 00725 // (control byte, and SRC MAC have already been set during init) 00726 #ifdef ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT 00727 // Check no transmit in progress 00728 00729 while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) { 00730 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. 00731 if ((readReg(EIR) & EIR_TXERIF)) { 00732 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); 00733 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); 00734 } 00735 } 00736 00737 #else 00738 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. 00739 00740 if ((readReg(EIR) & EIR_TXERIF)) { 00741 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); 00742 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); 00743 } 00744 #endif 00745 // Set the write pointer to start of transmit buffer area 00746 00747 // +1 to skip the per packet control byte and write directly the mac 00748 // The control byte was set to zero during initialisation and remains like that. 00749 writeReg(EWRPTL, (TXSTART_INIT + 1) & 0xFF); 00750 writeReg(EWRPTH, (TXSTART_INIT + 1) >> 8); 00751 // write a broadcase destination mac (all ff): 00752 while (i < 6) { 00753 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xFF); 00754 i++; 00755 } 00756 00757 // The mac in the ethernet field does not need to be changed. 00758 // Set the write pointer to the first byte of the EtherType field 00759 address = TXSTART_INIT + 1 + ETH_TYPE_H_P; 00760 writeReg(EWRPTL, address & 0xFF); 00761 writeReg(EWRPTH, address >> 8); 00762 // there are 10 fixed bytes in the arp request 00763 i = 0; 00764 while (i < 10) { 00765 writeOp(ENC28J60_WRITE_BUF_MEM, 0, (_arpReqHdr[i])); 00766 i++; 00767 } 00768 00769 i = 0; 00770 while (i < 6) { 00771 writeOp(ENC28J60_WRITE_BUF_MEM, 0, _mac[i]); 00772 i++; 00773 } 00774 00775 i = 0; 00776 while (i < 4) { 00777 writeOp(ENC28J60_WRITE_BUF_MEM, 0, _ip[i]); 00778 i++; 00779 } 00780 00781 // target data: 00782 i = 0; 00783 while (i < 6) { 00784 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0xff); 00785 i++; 00786 } 00787 00788 // to self, for gratuitous arp: 00789 i = 0; 00790 while (i < 4) { 00791 writeOp(ENC28J60_WRITE_BUF_MEM, 0, _ip[i]); 00792 i++; 00793 } 00794 00795 // Set the TXND pointer to correspond to the payload size given 00796 address = (TXSTART_INIT + 42); 00797 writeReg(ETXNDL, address & 0xFF); 00798 writeReg(ETXNDH, address >> 8); 00799 00800 // Send the contents of the transmit buffer onto the network 00801 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); 00802 } 00803 00804 /** 00805 * @brief 00806 * @note 00807 * @param 00808 * @retval 00809 */ 00810 void RawEthernet::send(uint8_t* buf, uint8_t len) 00811 { 00812 uint16_t address; 00813 setBank(0); 00814 00815 // (control byte, and SRC MAC have already been set during init) 00816 #ifdef ENC28J60_HAS_PENDING_TRANSMIT_ON_TRANSMIT 00817 // Check no transmit in progress 00818 00819 while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) { 00820 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. 00821 if ((readReg(EIR) & EIR_TXERIF)) { 00822 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); 00823 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); 00824 } 00825 } 00826 00827 #else 00828 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. 00829 00830 if ((readReg(EIR) & EIR_TXERIF)) { 00831 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); 00832 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); 00833 } 00834 #endif 00835 // Set the write pointer to start of transmit buffer area 00836 00837 // +1 to skip the per packet control byte and write directly the mac 00838 // The control byte was set to zero during initialisation and remains like that. 00839 writeReg(EWRPTL, (TXSTART_INIT + 1) & 0xFF); 00840 writeReg(EWRPTH, (TXSTART_INIT + 1) >> 8); 00841 writeBuffer(6, _remoteMac); 00842 00843 // Set the write pointer to the first byte of the EtherType field 00844 // (field after the mac address). This is the 802.3 length field. 00845 address = TXSTART_INIT + 1 + ETH_TYPE_H_P; 00846 writeReg(EWRPTL, address & 0xFF); 00847 writeReg(EWRPTH, address >> 8); 00848 // write the length of the data in the ethernet type field. 00849 // The type field to be interpreted by the receiver as ieee802.3 length if 00850 // the value is less than 0x05dc (see e.g. http://www.cavebear.com/archive/cavebear/Ethernet/type.html ): 00851 writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0); 00852 writeOp(ENC28J60_WRITE_BUF_MEM, 0, len); 00853 // Copy the payload into the transmit buffer 00854 writeBuffer(len, buf); // remove dest mac and write the rest 00855 // Set the TXND pointer to correspond to the payload size given 00856 address = (TXSTART_INIT + ETH_HEADER_LEN + len); 00857 writeReg(ETXNDL, address & 0xFF); 00858 writeReg(ETXNDH, address >> 8); 00859 00860 // Send the contents of the transmit buffer onto the network 00861 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); 00862 } 00863 00864 /** 00865 * @brief 00866 * @note 00867 * @param 00868 * @retval 00869 */ 00870 uint8_t RawEthernet::getRev(void) 00871 { 00872 uint8_t rev; 00873 00874 rev = readReg(EREVID); 00875 00876 // microchip forgott to step the number on the silcon when they 00877 // released the revision B7. 6 is now rev B7. We still have 00878 // to see what they do when they release B8. At the moment 00879 // there is no B8 out yet 00880 if (rev > 5) 00881 rev++; 00882 return(rev); 00883 } 00884
Generated on Sat Aug 6 2022 07:45:02 by
1.7.2