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