enc28j60_driver.c
Go to the documentation of this file.
1 /**
2  * @file enc28j60_driver.c
3  * @brief ENC28J60 Ethernet controller
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include <limits.h>
36 #include "core/net.h"
38 #include "debug.h"
39 
40 
41 /**
42  * @brief ENC28J60 driver
43  **/
44 
46 {
48  ETH_MTU,
56  NULL,
57  NULL,
58  NULL,
59  TRUE,
60  TRUE,
61  TRUE,
62  FALSE
63 };
64 
65 
66 /**
67  * @brief ENC28J60 controller initialization
68  * @param[in] interface Underlying network interface
69  * @return Error code
70  **/
71 
73 {
74  uint8_t revisionId;
75  Enc28j60Context *context;
76 
77  //Debug message
78  TRACE_INFO("Initializing ENC28J60 Ethernet controller...\r\n");
79 
80  //Initialize SPI
81  interface->spiDriver->init();
82  //Initialize external interrupt line
83  interface->extIntDriver->init();
84 
85  //Issue a system reset
86  enc28j60SoftReset(interface);
87 
88  //After issuing the reset command, wait at least 1ms in firmware
89  //for the device to be ready
90  sleep(10);
91 
92  //Point to the driver context
93  context = (Enc28j60Context *) interface->nicContext;
94 
95  //Initialize driver specific variables
96  context->currentBank = UINT16_MAX;
98 
99  //Allocate RX buffer
101  //Failed to allocate memory?
102  if(context->rxBuffer == NULL)
103  return ERROR_OUT_OF_MEMORY;
104 
105  //Read silicon revision ID
106  revisionId = enc28j60ReadReg(interface, ENC28J60_REG_EREVID);
107 
108  //Debug message
109  TRACE_INFO("ENC28J60 revision ID: 0x%02X\r\n", revisionId);
110 
111  //Disable CLKOUT output
112  enc28j60WriteReg(interface, ENC28J60_REG_ECOCON, 0x00);
113 
114  //Set the MAC address of the station
115  enc28j60WriteReg(interface, ENC28J60_REG_MAADR1, interface->macAddr.b[0]);
116  enc28j60WriteReg(interface, ENC28J60_REG_MAADR2, interface->macAddr.b[1]);
117  enc28j60WriteReg(interface, ENC28J60_REG_MAADR3, interface->macAddr.b[2]);
118  enc28j60WriteReg(interface, ENC28J60_REG_MAADR4, interface->macAddr.b[3]);
119  enc28j60WriteReg(interface, ENC28J60_REG_MAADR5, interface->macAddr.b[4]);
120  enc28j60WriteReg(interface, ENC28J60_REG_MAADR6, interface->macAddr.b[5]);
121 
122  //Set receive buffer location
127 
128  //The ERXRDPT register defines a location within the FIFO
129  //where the receive hardware is forbidden to write to
132 
133  //Configure the receive filters
136 
137  //Initialize the hash table
138  enc28j60WriteReg(interface, ENC28J60_REG_EHT0, 0x00);
139  enc28j60WriteReg(interface, ENC28J60_REG_EHT1, 0x00);
140  enc28j60WriteReg(interface, ENC28J60_REG_EHT2, 0x00);
141  enc28j60WriteReg(interface, ENC28J60_REG_EHT3, 0x00);
142  enc28j60WriteReg(interface, ENC28J60_REG_EHT4, 0x00);
143  enc28j60WriteReg(interface, ENC28J60_REG_EHT5, 0x00);
144  enc28j60WriteReg(interface, ENC28J60_REG_EHT6, 0x00);
145  enc28j60WriteReg(interface, ENC28J60_REG_EHT7, 0x00);
146 
147  //Pull the MAC out of reset
148  enc28j60WriteReg(interface, ENC28J60_REG_MACON2, 0x00);
149 
150  //Enable the MAC to receive frames
153 
154  //Enable automatic padding to at least 60 bytes, always append a valid CRC
155  //and check frame length. MAC can operate in half-duplex or full-duplex mode
156 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
159 #else
162 #endif
163 
164  //When the medium is occupied, the MAC will wait indefinitely for it to
165  //become free when attempting to transmit
167 
168  //Maximum frame length that can be received or transmitted
171 
172  //Configure the back-to-back inter-packet gap register
173 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
174  enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x15);
175 #else
176  enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x12);
177 #endif
178 
179  //Configure the non-back-to-back inter-packet gap register
180  enc28j60WriteReg(interface, ENC28J60_REG_MAIPGL, 0x12);
181  enc28j60WriteReg(interface, ENC28J60_REG_MAIPGH, 0x0C);
182 
183  //Collision window register
184  enc28j60WriteReg(interface, ENC28J60_REG_MACLCON2, 63);
185 
186  //Set the PHY to the proper duplex mode
187 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
189 #else
190  enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, 0x0000);
191 #endif
192 
193  //Disable half-duplex loopback in PHY
195 
196  //LEDA displays link status and LEDB displays TX/RX activity
199 
200  //Clear interrupt flags
201  enc28j60WriteReg(interface, ENC28J60_REG_EIR, 0x00);
202 
203  //Configure interrupts as desired
206 
207  //Configure PHY interrupts as desired
210 
211  //Set RXEN to enable reception
213 
214  //Dump registers for debugging purpose
215  enc28j60DumpReg(interface);
216  enc28j60DumpPhyReg(interface);
217 
218  //Accept any packets from the upper layer
219  osSetEvent(&interface->nicTxEvent);
220 
221  //Force the TCP/IP stack to poll the link state at startup
222  interface->nicEvent = TRUE;
223  //Notify the TCP/IP stack of the event
225 
226  //Successful initialization
227  return NO_ERROR;
228 }
229 
230 
231 /**
232  * @brief ENC28J60 timer handler
233  * @param[in] interface Underlying network interface
234  **/
235 
236 void enc28j60Tick(NetInterface *interface)
237 {
238 }
239 
240 
241 /**
242  * @brief Enable interrupts
243  * @param[in] interface Underlying network interface
244  **/
245 
247 {
248  //Enable interrupts
249  interface->extIntDriver->enableIrq();
250 }
251 
252 
253 /**
254  * @brief Disable interrupts
255  * @param[in] interface Underlying network interface
256  **/
257 
259 {
260  //Disable interrupts
261  interface->extIntDriver->disableIrq();
262 }
263 
264 
265 /**
266  * @brief ENC28J60 interrupt service routine
267  * @param[in] interface Underlying network interface
268  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
269  **/
270 
272 {
273  bool_t flag;
274  uint8_t status;
275 
276  //This flag will be set if a higher priority task must be woken
277  flag = FALSE;
278 
279  //Clear the INTIE bit, immediately after an interrupt event
281 
282  //Read interrupt status register
283  status = enc28j60ReadReg(interface, ENC28J60_REG_EIR);
284 
285  //Link status change?
286  if(status & EIR_LINKIF)
287  {
288  //Disable LINKIE interrupt
290 
291  //Set event flag
292  interface->nicEvent = TRUE;
293  //Notify the TCP/IP stack of the event
294  flag |= osSetEventFromIsr(&netEvent);
295  }
296 
297  //Packet received?
298  if(status & EIR_PKTIF)
299  {
300  //Disable PKTIE interrupt
302 
303  //Set event flag
304  interface->nicEvent = TRUE;
305  //Notify the TCP/IP stack of the event
306  flag |= osSetEventFromIsr(&netEvent);
307  }
308 
309  //Packet transmission complete?
310  if(status & (EIR_TXIF | EIE_TXERIE))
311  {
312  //Clear interrupt flags
314 
315  //Notify the TCP/IP stack that the transmitter is ready to send
316  flag |= osSetEventFromIsr(&interface->nicTxEvent);
317  }
318 
319  //Once the interrupt has been serviced, the INTIE bit
320  //is set again to re-enable interrupts
322 
323  //A higher priority task must be woken?
324  return flag;
325 }
326 
327 
328 /**
329  * @brief ENC28J60 event handler
330  * @param[in] interface Underlying network interface
331  **/
332 
334 {
335  error_t error;
336  uint16_t status;
337  uint16_t value;
338 
339  //Read interrupt status register
340  status = enc28j60ReadReg(interface, ENC28J60_REG_EIR);
341 
342  //Check whether the link state has changed
343  if(status & EIR_LINKIF)
344  {
345  //Clear PHY interrupts flags
347  //Clear interrupt flag
349  //Read PHY status register
351 
352  //Check link state
353  if(value & PHSTAT2_LSTAT)
354  {
355  //Link speed
356  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
357 
358 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
359  //Full-duplex mode
360  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
361 #else
362  //Half-duplex mode
363  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
364 #endif
365  //Link is up
366  interface->linkState = TRUE;
367  }
368  else
369  {
370  //Link is down
371  interface->linkState = FALSE;
372  }
373 
374  //Process link state change event
375  nicNotifyLinkChange(interface);
376  }
377 
378  //Check whether a packet has been received?
379  if(status & EIR_PKTIF)
380  {
381  //Clear interrupt flag
383 
384  //Process all pending packets
385  do
386  {
387  //Read incoming packet
388  error = enc28j60ReceivePacket(interface);
389 
390  //No more data in the receive buffer?
391  } while(error != ERROR_BUFFER_EMPTY);
392  }
393 
394  //Re-enable LINKIE and PKTIE interrupts
396 }
397 
398 
399 /**
400  * @brief Send a packet
401  * @param[in] interface Underlying network interface
402  * @param[in] buffer Multi-part buffer containing the data to send
403  * @param[in] offset Offset to the first data byte
404  * @return Error code
405  **/
406 
408  const NetBuffer *buffer, size_t offset)
409 {
410  size_t length;
411 
412  //Retrieve the length of the packet
413  length = netBufferGetLength(buffer) - offset;
414 
415  //Check the frame length
416  if(length > 1536)
417  {
418  //The transmitter can accept another packet
419  osSetEvent(&interface->nicTxEvent);
420  //Report an error
421  return ERROR_INVALID_LENGTH;
422  }
423 
424  //Make sure the link is up before transmitting the frame
425  if(!interface->linkState)
426  {
427  //The transmitter can accept another packet
428  osSetEvent(&interface->nicTxEvent);
429  //Drop current packet
430  return NO_ERROR;
431  }
432 
433  //It is recommended to reset the transmit logic before
434  //attempting to transmit a packet
437 
438  //Interrupt flags should be cleared after the reset is completed
440 
441  //Set transmit buffer location
444 
445  //Point to start of transmit buffer
448 
449  //Copy the data to the transmit buffer
450  enc28j60WriteBuffer(interface, buffer, offset);
451 
452  //ETXND should point to the last byte in the data payload
455 
456  //Start transmission
458 
459  //Successful processing
460  return NO_ERROR;
461 }
462 
463 
464 /**
465  * @brief Receive a packet
466  * @param[in] interface Underlying network interface
467  * @return Error code
468  **/
469 
471 {
472  error_t error;
473  uint16_t n;
474  uint16_t status;
475  Enc28j60Context *context;
476 
477  //Point to the driver context
478  context = (Enc28j60Context *) interface->nicContext;
479 
480  //Any packet pending in the receive buffer?
481  if(enc28j60ReadReg(interface, ENC28J60_REG_EPKTCNT))
482  {
483  //Point to the start of the received packet
484  enc28j60WriteReg(interface, ENC28J60_REG_ERDPTL, LSB(context->nextPacket));
485  enc28j60WriteReg(interface, ENC28J60_REG_ERDPTH, MSB(context->nextPacket));
486 
487  //Read the first two bytes, which are the address of the next packet
488  enc28j60ReadBuffer(interface, (uint8_t *) &context->nextPacket, sizeof(uint16_t));
489  //Get the length of the received frame in bytes
490  enc28j60ReadBuffer(interface, (uint8_t *) &n, sizeof(uint16_t));
491  //Read the receive status vector (RSV)
492  enc28j60ReadBuffer(interface, (uint8_t *) &status, sizeof(uint16_t));
493 
494  //Make sure no error occurred
495  if(status & RSV_RECEIVED_OK)
496  {
497  //Limit the number of data to read
499  //Read the Ethernet frame
500  enc28j60ReadBuffer(interface, context->rxBuffer, n);
501  //Valid packet received
502  error = NO_ERROR;
503  }
504  else
505  {
506  //The received packet contains an error
507  error = ERROR_INVALID_PACKET;
508  }
509 
510  //Advance the ERXRDPT pointer, taking care to wrap back at the
511  //end of the received memory buffer
512  if(context->nextPacket == ENC28J60_RX_BUFFER_START)
513  {
516  }
517  else
518  {
519  enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(context->nextPacket - 1));
520  enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(context->nextPacket - 1));
521  }
522 
523  //Decrement the packet counter
525  }
526  else
527  {
528  //No more data in the receive buffer
529  error = ERROR_BUFFER_EMPTY;
530  }
531 
532  //Check whether a valid packet has been received
533  if(!error)
534  {
535  //Pass the packet to the upper layer
536  nicProcessPacket(interface, context->rxBuffer, n);
537  }
538 
539  //Return status code
540  return error;
541 }
542 
543 
544 /**
545  * @brief Configure MAC address filtering
546  * @param[in] interface Underlying network interface
547  * @return Error code
548  **/
549 
551 {
552  uint_t i;
553  uint_t k;
554  uint32_t crc;
555  uint8_t hashTable[8];
556  MacFilterEntry *entry;
557 
558  //Debug message
559  TRACE_DEBUG("Updating MAC filter...\r\n");
560 
561  //Clear hash table
562  memset(hashTable, 0, sizeof(hashTable));
563 
564  //The MAC address filter contains the list of MAC addresses to accept
565  //when receiving an Ethernet frame
566  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
567  {
568  //Point to the current entry
569  entry = &interface->macAddrFilter[i];
570 
571  //Valid entry?
572  if(entry->refCount > 0)
573  {
574  //Compute CRC over the current MAC address
575  crc = enc28j60CalcCrc(&entry->addr, sizeof(MacAddr));
576  //Calculate the corresponding index in the table
577  k = (crc >> 23) & 0x3F;
578  //Update hash table contents
579  hashTable[k / 8] |= (1 << (k % 8));
580  }
581  }
582 
583  //Write the hash table to the ENC28J60 controller
584  enc28j60WriteReg(interface, ENC28J60_REG_EHT0, hashTable[0]);
585  enc28j60WriteReg(interface, ENC28J60_REG_EHT1, hashTable[1]);
586  enc28j60WriteReg(interface, ENC28J60_REG_EHT2, hashTable[2]);
587  enc28j60WriteReg(interface, ENC28J60_REG_EHT3, hashTable[3]);
588  enc28j60WriteReg(interface, ENC28J60_REG_EHT4, hashTable[4]);
589  enc28j60WriteReg(interface, ENC28J60_REG_EHT5, hashTable[5]);
590  enc28j60WriteReg(interface, ENC28J60_REG_EHT6, hashTable[6]);
591  enc28j60WriteReg(interface, ENC28J60_REG_EHT7, hashTable[7]);
592 
593  //Debug message
594  TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT0));
595  TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT1));
596  TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT2));
597  TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT3));
598  TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT4));
599  TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT5));
600  TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT6));
601  TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT7));
602 
603  //Successful processing
604  return NO_ERROR;
605 }
606 
607 
608 /**
609  * @brief ENC28J60 controller reset
610  * @param[in] interface Underlying network interface
611  **/
612 
614 {
615  //Pull the CS pin low
616  interface->spiDriver->assertCs();
617 
618  //Write opcode
619  interface->spiDriver->transfer(ENC28J60_CMD_SRC);
620 
621  //Terminate the operation by raising the CS pin
622  interface->spiDriver->deassertCs();
623 }
624 
625 
626 /**
627  * @brief Bank selection
628  * @param[in] interface Underlying network interface
629  * @param[in] address Register address
630  **/
631 
632 void enc28j60SelectBank(NetInterface *interface, uint16_t address)
633 {
634  uint16_t bank;
635  Enc28j60Context *context;
636 
637  //Point to the driver context
638  context = (Enc28j60Context *) interface->nicContext;
639 
640  //Get the bank number from the specified address
641  bank = address & REG_BANK_MASK;
642 
643  //Rewrite the bank number only if a change is detected
644  if(bank != context->currentBank)
645  {
646  //Select specified bank
647  switch(bank)
648  {
649  case BANK_0:
650  //Select bank 0
652  break;
653  case BANK_1:
654  //Select bank 1
657  break;
658  case BANK_2:
659  //Select bank 2
662  break;
663  case BANK_3:
664  //Select bank 3
666  break;
667  default:
668  //Invalid bank
669  break;
670  }
671 
672  //Save bank number
673  context->currentBank = bank;
674  }
675 }
676 
677 
678 /**
679  * @brief Write ENC28J60 register
680  * @param[in] interface Underlying network interface
681  * @param[in] address Register address
682  * @param[in] data Register value
683  **/
684 
685 void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data)
686 {
687  //Make sure the corresponding bank is selected
688  enc28j60SelectBank(interface, address);
689 
690  //Pull the CS pin low
691  interface->spiDriver->assertCs();
692 
693  //Write opcode and register address
694  interface->spiDriver->transfer(ENC28J60_CMD_WCR | (address & REG_ADDR_MASK));
695  //Write register value
696  interface->spiDriver->transfer(data);
697 
698  //Terminate the operation by raising the CS pin
699  interface->spiDriver->deassertCs();
700 }
701 
702 
703 /**
704  * @brief Read ENC28J60 register
705  * @param[in] interface Underlying network interface
706  * @param[in] address Register address
707  * @return Register value
708  **/
709 
710 uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address)
711 {
712  uint16_t data;
713 
714  //Make sure the corresponding bank is selected
715  enc28j60SelectBank(interface, address);
716 
717  //Pull the CS pin low
718  interface->spiDriver->assertCs();
719 
720  //Write opcode and register address
721  interface->spiDriver->transfer(ENC28J60_CMD_RCR | (address & REG_ADDR_MASK));
722 
723  //When reading MAC or MII registers, a dummy byte is first shifted out
725  interface->spiDriver->transfer(0x00);
726 
727  //Read register contents
728  data = interface->spiDriver->transfer(0x00);
729 
730  //Terminate the operation by raising the CS pin
731  interface->spiDriver->deassertCs();
732 
733  //Return register contents
734  return data;
735 }
736 
737 
738 /**
739  * @brief Write PHY register
740  * @param[in] interface Underlying network interface
741  * @param[in] address PHY register address
742  * @param[in] data Register value
743  **/
744 
745 void enc28j60WritePhyReg(NetInterface *interface, uint16_t address,
746  uint16_t data)
747 {
748  //Write register address
750 
751  //Write the lower 8 bits
753  //Write the upper 8 bits
755 
756  //Wait until the PHY register has been written
757  while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY);
758 }
759 
760 
761 /**
762  * @brief Read PHY register
763  * @param[in] interface Underlying network interface
764  * @param[in] address PHY register address
765  * @return Register value
766  **/
767 
768 uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address)
769 {
770  uint16_t data;
771 
772  //Write register address
774 
775  //Start read operation
777  //Wait for the read operation to complete
778  while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY);
779  //Clear command register
780  enc28j60WriteReg(interface, ENC28J60_REG_MICMD, 0);
781 
782  //Read the lower 8 bits
784  //Read the upper 8 bits
785  data |= enc28j60ReadReg(interface, ENC28J60_REG_MIRDH) << 8;
786 
787  //Return register contents
788  return data;
789 }
790 
791 
792 /**
793  * @brief Write SRAM buffer
794  * @param[in] interface Underlying network interface
795  * @param[in] buffer Multi-part buffer containing the data to be written
796  * @param[in] offset Offset to the first data byte
797  **/
798 
800  const NetBuffer *buffer, size_t offset)
801 {
802  uint_t i;
803  size_t j;
804  size_t n;
805  uint8_t *p;
806 
807  //Pull the CS pin low
808  interface->spiDriver->assertCs();
809 
810  //Write opcode
811  interface->spiDriver->transfer(ENC28J60_CMD_WBM);
812  //Write per-packet control byte
813  interface->spiDriver->transfer(0x00);
814 
815  //Loop through data chunks
816  for(i = 0; i < buffer->chunkCount; i++)
817  {
818  //Is there any data to copy from the current chunk?
819  if(offset < buffer->chunk[i].length)
820  {
821  //Point to the first byte to be read
822  p = (uint8_t *) buffer->chunk[i].address + offset;
823  //Compute the number of bytes to copy at a time
824  n = buffer->chunk[i].length - offset;
825 
826  //Copy data to SRAM buffer
827  for(j = 0; j < n; j++)
828  interface->spiDriver->transfer(p[j]);
829 
830  //Process the next block from the start
831  offset = 0;
832  }
833  else
834  {
835  //Skip the current chunk
836  offset -= buffer->chunk[i].length;
837  }
838  }
839 
840  //Terminate the operation by raising the CS pin
841  interface->spiDriver->deassertCs();
842 }
843 
844 
845 /**
846  * @brief Read SRAM buffer
847  * @param[in] interface Underlying network interface
848  * @param[in] data Buffer where to store the incoming data
849  * @param[in] length Number of data to read
850  **/
851 
853  uint8_t *data, size_t length)
854 {
855  size_t i;
856 
857  //Pull the CS pin low
858  interface->spiDriver->assertCs();
859 
860  //Write opcode
861  interface->spiDriver->transfer(ENC28J60_CMD_RBM);
862 
863  //Copy data from SRAM buffer
864  for(i = 0; i < length; i++)
865  data[i] = interface->spiDriver->transfer(0x00);
866 
867  //Terminate the operation by raising the CS pin
868  interface->spiDriver->deassertCs();
869 }
870 
871 
872 /**
873  * @brief Set bit field
874  * @param[in] interface Underlying network interface
875  * @param[in] address Register address
876  * @param[in] mask Bits to set in the target register
877  **/
878 
879 void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask)
880 {
881  //Pull the CS pin low
882  interface->spiDriver->assertCs();
883 
884  //Write opcode and register address
885  interface->spiDriver->transfer(ENC28J60_CMD_BFS | (address & REG_ADDR_MASK));
886  //Write bit mask
887  interface->spiDriver->transfer(mask);
888 
889  //Terminate the operation by raising the CS pin
890  interface->spiDriver->deassertCs();
891 }
892 
893 
894 /**
895  * @brief Clear bit field
896  * @param[in] interface Underlying network interface
897  * @param[in] address Register address
898  * @param[in] mask Bits to clear in the target register
899  **/
900 
901 void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask)
902 {
903  //Pull the CS pin low
904  interface->spiDriver->assertCs();
905 
906  //Write opcode and register address
907  interface->spiDriver->transfer(ENC28J60_CMD_BFC | (address & REG_ADDR_MASK));
908  //Write bit mask
909  interface->spiDriver->transfer(mask);
910 
911  //Terminate the operation by raising the CS pin
912  interface->spiDriver->deassertCs();
913 }
914 
915 
916 /**
917  * @brief CRC calculation using the polynomial 0x4C11DB7
918  * @param[in] data Pointer to the data over which to calculate the CRC
919  * @param[in] length Number of bytes to process
920  * @return Resulting CRC value
921  **/
922 
923 uint32_t enc28j60CalcCrc(const void *data, size_t length)
924 {
925  uint_t i;
926  uint_t j;
927 
928  //Point to the data over which to calculate the CRC
929  const uint8_t *p = (uint8_t *) data;
930  //CRC preset value
931  uint32_t crc = 0xFFFFFFFF;
932 
933  //Loop through data
934  for(i = 0; i < length; i++)
935  {
936  //The message is processed bit by bit
937  for(j = 0; j < 8; j++)
938  {
939  //Update CRC value
940  if(((crc >> 31) ^ (p[i] >> j)) & 0x01)
941  crc = (crc << 1) ^ 0x04C11DB7;
942  else
943  crc = crc << 1;
944  }
945  }
946 
947  //Return CRC value
948  return crc;
949 }
950 
951 
952 /**
953  * @brief Dump registers for debugging purpose
954  * @param[in] interface Underlying network interface
955  **/
956 
958 {
959 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
960  uint8_t i;
961  uint8_t bank;
962  uint16_t address;
963 
964  //Display header
965  TRACE_DEBUG(" Bank 0 Bank 1 Bank 2 Bank 3\r\n");
966 
967  //Loop through register addresses
968  for(i = 0; i < 32; i++)
969  {
970  //Display register address
971  TRACE_DEBUG("%02" PRIX8 ": ", i);
972 
973  //Loop through bank numbers
974  for(bank = 0; bank < 4; bank++)
975  {
976  //Format register address
977  address = (bank << 8) | i;
978 
979  //MAC and MII registers require a specific read sequence
980  if(address >= 0x200 && address <= 0x219)
982  else if(address >= 0x300 && address <= 0x305)
984  else if(address == 0x30A)
986 
987  //Display register contents
988  TRACE_DEBUG("0x%02" PRIX8 " ", enc28j60ReadReg(interface, address));
989  }
990 
991  //Jump to the following line
992  TRACE_DEBUG("\r\n");
993  }
994 
995  //Terminate with a line feed
996  TRACE_DEBUG("\r\n");
997 #endif
998 }
999 
1000 
1001 /**
1002  * @brief Dump PHY registers for debugging purpose
1003  * @param[in] interface Underlying network interface
1004  **/
1005 
1007 {
1008 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
1009  uint8_t i;
1010 
1011  //Loop through PHY registers
1012  for(i = 0; i < 32; i++)
1013  {
1014  //Display current PHY register
1015  TRACE_DEBUG("%02" PRIX8 ": 0x%04" PRIX16 "\r\n", i,
1016  enc28j60ReadPhyReg(interface, i));
1017  }
1018 
1019  //Terminate with a line feed
1020  TRACE_DEBUG("\r\n");
1021 #endif
1022 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:525
#define ENC28J60_REG_MISTAT
#define ENC28J60_REG_MICMD
uint8_t length
Definition: dtls_misc.h:149
uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address)
Read ENC28J60 register.
bool_t enc28j60IrqHandler(NetInterface *interface)
ENC28J60 interrupt service routine.
#define EIR_PKTIF
int bool_t
Definition: compiler_port.h:49
#define PHIE_PLNKIE
void enc28j60ReadBuffer(NetInterface *interface, uint8_t *data, size_t length)
Read SRAM buffer.
#define ENC28J60_CMD_SRC
#define ENC28J60_REG_MACLCON2
uint8_t * rxBuffer
Receive buffer.
#define ENC28J60_CMD_WCR
#define ENC28J60_RX_BUFFER_START
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:119
#define ENC28J60_REG_ECON1
#define ENC28J60_REG_ECOCON
#define ENC28J60_REG_MAIPGL
#define MICMD_MIIRD
#define ENC28J60_REG_EHT6
uint8_t p
Definition: ndp.h:298
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:383
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
uint_t chunkCount
Definition: net_mem.h:90
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:74
#define ENC28J60_REG_MIRDL
#define TRUE
Definition: os_port.h:50
#define sleep(delay)
Definition: os_port.h:131
#define ETH_MAX_FRAME_SIZE
Definition: ethernet.h:89
#define ENC28J60_TX_BUFFER_START
#define EIR_TXIF
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:223
#define EIE_TXERIE
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
error_t enc28j60SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
#define ENC28J60_REG_EWRPTL
#define MACON3_FULDPX
#define REG_TYPE_MASK
#define ENC28J60_REG_MACON3
#define ENC28J60_REG_MIRDH
void enc28j60SoftReset(NetInterface *interface)
ENC28J60 controller reset.
void * memPoolAlloc(size_t size)
Allocate a memory block.
Definition: net_mem.c:100
#define BANK_3
#define ENC28J60_REG_EHT2
#define ENC28J60_REG_MAADR6
#define PHCON1_PDPXMD
#define ENC28J60_REG_EIE
void enc28j60WritePhyReg(NetInterface *interface, uint16_t address, uint16_t data)
Write PHY register.
#define ENC28J60_REG_ERXNDL
#define ENC28J60_REG_EREVID
#define ENC28J60_REG_EHT3
#define ERXFCON_UCEN
#define EIR_TXERIF
#define EIR_LINKIF
#define ENC28J60_REG_EHT1
#define ENC28J60_REG_ERXFCON
ENC28J60 Ethernet controller.
#define BANK_2
#define EIE_TXIE
#define MISTAT_BUSY
#define ECON1_TXRTS
#define ENC28J60_REG_ERXSTH
#define ENC28J60_REG_EHT7
#define ECON1_RXEN
uint16_t length
Definition: net_mem.h:79
#define FALSE
Definition: os_port.h:46
void enc28j60DumpReg(NetInterface *interface)
Dump registers for debugging purpose.
void enc28j60EnableIrq(NetInterface *interface)
Enable interrupts.
uint16_t nextPacket
Next packet in the receive buffer.
#define REG_BANK_MASK
error_t
Error codes.
Definition: error.h:42
#define ENC28J60_PHY_REG_PHSTAT2
#define REG_ADDR_MASK
void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data)
Write ENC28J60 register.
void enc28j60DisableIrq(NetInterface *interface)
Disable interrupts.
#define ENC28J60_RX_BUFFER_STOP
void enc28j60WriteBuffer(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Write SRAM buffer.
#define ENC28J60_REG_MIWRL
void enc28j60DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
void * address
Definition: net_mem.h:78
#define ENC28J60_REG_MAMXFLL
uint32_t enc28j60CalcCrc(const void *data, size_t length)
CRC calculation using the polynomial 0x4C11DB7.
const NicDriver enc28j60Driver
ENC28J60 driver.
#define ERXFCON_BCEN
@ ERROR_INVALID_PACKET
Definition: error.h:138
#define ECON1_TXRST
#define NetInterface
Definition: net.h:36
#define MACON3_FRMLNEN
MacAddr addr
MAC address.
Definition: ethernet.h:222
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:105
#define ENC28J60_PHY_REG_PHIE
uint16_t currentBank
Current bank.
@ ERROR_INVALID_LENGTH
Definition: error.h:109
#define ECON2_PKTDEC
#define PHIE_PGEIE
@ ERROR_BUFFER_EMPTY
Definition: error.h:139
#define ENC28J60_REG_MACON1
#define PHLCON_STRCH
#define ENC28J60_REG_MAADR3
#define BANK_1
uint8_t mask
Definition: web_socket.h:317
#define ENC28J60_REG_EHT5
#define ENC28J60_REG_ETXSTL
#define ENC28J60_CMD_BFS
OsEvent netEvent
Definition: net.c:77
#define EIE_PKTIE
#define MSB(x)
Definition: os_port.h:58
#define ENC28J60_REG_MAADR5
#define TRACE_INFO(...)
Definition: debug.h:94
void enc28j60EventHandler(NetInterface *interface)
ENC28J60 event handler.
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define LSB(x)
Definition: os_port.h:54
#define ENC28J60_REG_EHT4
#define ENC28J60_REG_MACON2
#define BANK_0
#define MIN(a, b)
Definition: os_port.h:62
#define ENC28J60_PHY_REG_PHCON1
#define ENC28J60_REG_MIWRH
void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask)
Set bit field.
#define ENC28J60_CMD_RBM
#define MACON3_TXCRCEN
#define ETH_REG_TYPE
#define MACON4_DEFER
#define ENC28J60_REG_MAADR2
#define MACON1_TXPAUS
#define ENC28J60_CMD_RCR
#define ENC28J60_REG_ERDPTL
#define MACON1_RXPAUS
#define ENC28J60_REG_MAIPGH
#define TRACE_DEBUG(...)
Definition: debug.h:106
ENC28J60 driver context.
#define ENC28J60_REG_ECON2
#define PHLCON_LBCFG(x)
ChunkDesc chunk[]
Definition: net_mem.h:92
#define ENC28J60_REG_MIREGADR
#define ENC28J60_REG_ERXRDPTH
#define RSV_RECEIVED_OK
#define ETH_MTU
Definition: ethernet.h:91
uint8_t n
MAC filter table entry.
Definition: ethernet.h:220
#define MACON1_MARXEN
#define MACON3_PADCFG(x)
#define ENC28J60_REG_MAMXFLH
#define ECON1_BSEL1
uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address)
Read PHY register.
#define ENC28J60_CMD_WBM
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:118
#define PHCON2_HDLDIS
#define ENC28J60_PHY_REG_PHIR
#define ENC28J60_PHY_REG_PHLCON
#define ENC28J60_REG_ETXNDH
#define ENC28J60_REG_ERDPTH
#define ENC28J60_REG_MACON4
#define ENC28J60_REG_EWRPTH
error_t enc28j60UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
Ipv6Addr address
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ENC28J60_REG_EHT0
#define ENC28J60_REG_MABBIPG
#define ENC28J60_REG_EPKTCNT
#define ERXFCON_HTEN
#define ENC28J60_REG_MAADR1
#define EIE_LINKIE
#define ENC28J60_REG_ETXSTH
#define PHLCON_LFRQ(x)
void enc28j60Tick(NetInterface *interface)
ENC28J60 timer handler.
#define ENC28J60_CMD_BFC
uint8_t value[]
Definition: dtls_misc.h:150
error_t enc28j60Init(NetInterface *interface)
ENC28J60 controller initialization.
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
uint8_t data[]
Definition: dtls_misc.h:176
NIC driver.
Definition: nic.h:179
#define MAC_REG_TYPE
#define ENC28J60_REG_ETXNDL
#define ENC28J60_PHY_REG_PHCON2
#define ENC28J60_REG_ERXSTL
#define ENC28J60_REG_ERXNDH
void enc28j60SelectBank(NetInterface *interface, uint16_t address)
Bank selection.
void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask)
Clear bit field.
#define ERXFCON_CRCEN
#define PHSTAT2_LSTAT
#define ENC28J60_REG_EIR
error_t enc28j60ReceivePacket(NetInterface *interface)
Receive a packet.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define ENC28J60_REG_ERXRDPTL
__start_packed struct @108 MacAddr
MAC address.
#define ENC28J60_REG_MAADR4
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:79
#define PHLCON_LACFG(x)
#define EIE_INTIE
#define ECON1_BSEL0