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-2024 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 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
37 #include "debug.h"
38 
39 
40 /**
41  * @brief ENC28J60 driver
42  **/
43 
45 {
47  ETH_MTU,
55  NULL,
56  NULL,
57  NULL,
58  TRUE,
59  TRUE,
60  TRUE,
61  FALSE
62 };
63 
64 
65 /**
66  * @brief ENC28J60 controller initialization
67  * @param[in] interface Underlying network interface
68  * @return Error code
69  **/
70 
72 {
73  uint8_t revisionId;
74  Enc28j60Context *context;
75 
76  //Debug message
77  TRACE_INFO("Initializing ENC28J60 Ethernet controller...\r\n");
78 
79  //Initialize SPI interface
80  interface->spiDriver->init();
81 
82  //Initialize external interrupt line driver
83  if(interface->extIntDriver != NULL)
84  {
85  interface->extIntDriver->init();
86  }
87 
88  //Issue a system reset
89  enc28j60SoftReset(interface);
90 
91  //After issuing the reset command, wait at least 1ms in firmware
92  //for the device to be ready
93  sleep(10);
94 
95  //Point to the driver context
96  context = (Enc28j60Context *) interface->nicContext;
97 
98  //Initialize driver specific variables
99  context->currentBank = UINT16_MAX;
101 
102  //Read silicon revision ID
103  revisionId = enc28j60ReadReg(interface, ENC28J60_EREVID);
104 
105  //Debug message
106  TRACE_INFO("ENC28J60 revision ID: 0x%02X\r\n", revisionId);
107 
108  //Disable CLKOUT output
110 
111  //Set the MAC address of the station
112  enc28j60WriteReg(interface, ENC28J60_MAADR5, interface->macAddr.b[0]);
113  enc28j60WriteReg(interface, ENC28J60_MAADR4, interface->macAddr.b[1]);
114  enc28j60WriteReg(interface, ENC28J60_MAADR3, interface->macAddr.b[2]);
115  enc28j60WriteReg(interface, ENC28J60_MAADR2, interface->macAddr.b[3]);
116  enc28j60WriteReg(interface, ENC28J60_MAADR1, interface->macAddr.b[4]);
117  enc28j60WriteReg(interface, ENC28J60_MAADR0, interface->macAddr.b[5]);
118 
119  //Set receive buffer location
124 
125  //The ERXRDPT register defines a location within the FIFO where the receive
126  //hardware is forbidden to write to
129 
130  //Configure the receive filters
133 
134  //Initialize the hash table
135  enc28j60WriteReg(interface, ENC28J60_EHT0, 0x00);
136  enc28j60WriteReg(interface, ENC28J60_EHT1, 0x00);
137  enc28j60WriteReg(interface, ENC28J60_EHT2, 0x00);
138  enc28j60WriteReg(interface, ENC28J60_EHT3, 0x00);
139  enc28j60WriteReg(interface, ENC28J60_EHT4, 0x00);
140  enc28j60WriteReg(interface, ENC28J60_EHT5, 0x00);
141  enc28j60WriteReg(interface, ENC28J60_EHT6, 0x00);
142  enc28j60WriteReg(interface, ENC28J60_EHT7, 0x00);
143 
144  //Pull the MAC out of reset
145  enc28j60WriteReg(interface, ENC28J60_MACON2, 0x00);
146 
147  //Enable the MAC to receive frames
150 
151  //Enable automatic padding, always append a valid CRC and check frame
152  //length. MAC can operate in half-duplex or full-duplex mode
153 #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
169 
170  //Configure the back-to-back inter-packet gap register
171 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
173 #else
175 #endif
176 
177  //Configure the non-back-to-back inter-packet gap register
180 
181  //Collision window register
184 
185  //Set the PHY to the proper duplex mode
186 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
188 #else
189  enc28j60WritePhyReg(interface, ENC28J60_PHCON1, 0x0000);
190 #endif
191 
192  //Disable half-duplex loopback in PHY
194 
195  //LEDA displays link status and LEDB displays TX/RX activity
199 
200  //Clear interrupt flags
201  enc28j60WriteReg(interface, ENC28J60_EIR, 0x00);
202 
203  //Configure interrupts as desired
207 
208  //Configure PHY interrupts as desired
211 
212  //Set RXEN to enable reception
214 
215  //Perform custom configuration
216  enc28j60InitHook(interface);
217 
218  //Dump registers for debugging purpose
219  enc28j60DumpReg(interface);
220  enc28j60DumpPhyReg(interface);
221 
222  //Accept any packets from the upper layer
223  osSetEvent(&interface->nicTxEvent);
224 
225  //Force the TCP/IP stack to poll the link state at startup
226  interface->nicEvent = TRUE;
227  //Notify the TCP/IP stack of the event
229 
230  //Successful initialization
231  return NO_ERROR;
232 }
233 
234 
235 /**
236  * @brief ENC28J60 custom configuration
237  * @param[in] interface Underlying network interface
238  **/
239 
240 __weak_func void enc28j60InitHook(NetInterface *interface)
241 {
242 }
243 
244 
245 /**
246  * @brief ENC28J60 timer handler
247  * @param[in] interface Underlying network interface
248  **/
249 
250 void enc28j60Tick(NetInterface *interface)
251 {
252 }
253 
254 
255 /**
256  * @brief Enable interrupts
257  * @param[in] interface Underlying network interface
258  **/
259 
261 {
262  //Enable interrupts
263  if(interface->extIntDriver != NULL)
264  {
265  interface->extIntDriver->enableIrq();
266  }
267 }
268 
269 
270 /**
271  * @brief Disable interrupts
272  * @param[in] interface Underlying network interface
273  **/
274 
276 {
277  //Disable interrupts
278  if(interface->extIntDriver != NULL)
279  {
280  interface->extIntDriver->disableIrq();
281  }
282 }
283 
284 
285 /**
286  * @brief ENC28J60 interrupt service routine
287  * @param[in] interface Underlying network interface
288  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
289  **/
290 
292 {
293  bool_t flag;
294  uint8_t status;
295 
296  //This flag will be set if a higher priority task must be woken
297  flag = FALSE;
298 
299  //Clear the INTIE bit, immediately after an interrupt event
301 
302  //Read interrupt status register
303  status = enc28j60ReadReg(interface, ENC28J60_EIR);
304 
305  //Link status change?
306  if((status & ENC28J60_EIR_LINKIF) != 0)
307  {
308  //Disable LINKIE interrupt
310 
311  //Set event flag
312  interface->nicEvent = TRUE;
313  //Notify the TCP/IP stack of the event
314  flag |= osSetEventFromIsr(&netEvent);
315  }
316 
317  //Packet received?
318  if(enc28j60ReadReg(interface, ENC28J60_EPKTCNT) != 0)
319  {
320  //Disable PKTIE interrupt
322 
323  //Set event flag
324  interface->nicEvent = TRUE;
325  //Notify the TCP/IP stack of the event
326  flag |= osSetEventFromIsr(&netEvent);
327  }
328 
329  //Packet transmission complete?
330  if((status & (ENC28J60_EIR_TXIF | ENC28J60_EIE_TXERIE)) != 0)
331  {
332  //Clear interrupt flags
335 
336  //Notify the TCP/IP stack that the transmitter is ready to send
337  flag |= osSetEventFromIsr(&interface->nicTxEvent);
338  }
339 
340  //Once the interrupt has been serviced, the INTIE bit is set again to
341  //re-enable interrupts
343 
344  //A higher priority task must be woken?
345  return flag;
346 }
347 
348 
349 /**
350  * @brief ENC28J60 event handler
351  * @param[in] interface Underlying network interface
352  **/
353 
355 {
356  error_t error;
357  uint16_t status;
358  uint16_t value;
359 
360  //Read interrupt status register
361  status = enc28j60ReadReg(interface, ENC28J60_EIR);
362 
363  //Check whether the link state has changed
364  if((status & ENC28J60_EIR_LINKIF) != 0)
365  {
366  //Clear PHY interrupts flags
367  enc28j60ReadPhyReg(interface, ENC28J60_PHIR);
368  //Clear interrupt flag
370  //Read PHY status register
372 
373  //Check link state
374  if((value & ENC28J60_PHSTAT2_LSTAT) != 0)
375  {
376  //The PHY is only able to operate in 10 Mbps mode
377  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
378 
379 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
380  //Full-duplex mode
381  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
382 #else
383  //Half-duplex mode
384  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
385 #endif
386  //Link is up
387  interface->linkState = TRUE;
388  }
389  else
390  {
391  //Link is down
392  interface->linkState = FALSE;
393  }
394 
395  //Process link state change event
396  nicNotifyLinkChange(interface);
397  }
398 
399  //Check whether a packet has been received?
400  if(enc28j60ReadReg(interface, ENC28J60_EPKTCNT) != 0)
401  {
402  //Clear interrupt flag
404 
405  //Process all pending packets
406  do
407  {
408  //Read incoming packet
409  error = enc28j60ReceivePacket(interface);
410 
411  //No more data in the receive buffer?
412  } while(error != ERROR_BUFFER_EMPTY);
413  }
414 
415  //Re-enable LINKIE and PKTIE interrupts
418 }
419 
420 
421 /**
422  * @brief Send a packet
423  * @param[in] interface Underlying network interface
424  * @param[in] buffer Multi-part buffer containing the data to send
425  * @param[in] offset Offset to the first data byte
426  * @param[in] ancillary Additional options passed to the stack along with
427  * the packet
428  * @return Error code
429  **/
430 
432  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
433 {
434  size_t length;
435 
436  //Retrieve the length of the packet
437  length = netBufferGetLength(buffer) - offset;
438 
439  //Check the frame length
440  if(length > 1536)
441  {
442  //The transmitter can accept another packet
443  osSetEvent(&interface->nicTxEvent);
444  //Report an error
445  return ERROR_INVALID_LENGTH;
446  }
447 
448  //Make sure the link is up before transmitting the frame
449  if(!interface->linkState)
450  {
451  //The transmitter can accept another packet
452  osSetEvent(&interface->nicTxEvent);
453  //Drop current packet
454  return NO_ERROR;
455  }
456 
457  //It is recommended to reset the transmit logic before
458  //attempting to transmit a packet
461 
462  //Interrupt flags should be cleared after the reset is completed
465 
466  //Set transmit buffer location
469 
470  //Point to start of transmit buffer
473 
474  //Copy the data to the transmit buffer
475  enc28j60WriteBuffer(interface, buffer, offset);
476 
477  //ETXND should point to the last byte in the data payload
480 
481  //Start transmission
483 
484  //Successful processing
485  return NO_ERROR;
486 }
487 
488 
489 /**
490  * @brief Receive a packet
491  * @param[in] interface Underlying network interface
492  * @return Error code
493  **/
494 
496 {
497  static uint8_t temp[ENC28J60_ETH_RX_BUFFER_SIZE];
498  error_t error;
499  uint16_t length;
500  uint16_t status;
501  uint8_t header[6];
502  Enc28j60Context *context;
503 
504  //Point to the driver context
505  context = (Enc28j60Context *) interface->nicContext;
506 
507  //Any packet pending in the receive buffer?
508  if(enc28j60ReadReg(interface, ENC28J60_EPKTCNT) != 0)
509  {
510  //Point to the start of the received packet
511  enc28j60WriteReg(interface, ENC28J60_ERDPTL, LSB(context->nextPacket));
512  enc28j60WriteReg(interface, ENC28J60_ERDPTH, MSB(context->nextPacket));
513 
514  //The packet is preceded by a 6-byte header
515  enc28j60ReadBuffer(interface, header, sizeof(header));
516 
517  //The first two bytes are the address of the next packet
518  context->nextPacket = LOAD16LE(header);
519  //Get the length of the received packet
520  length = LOAD16LE(header + 2);
521  //Get the receive status vector (RSV)
522  status = LOAD16LE(header + 4);
523 
524  //Make sure no error occurred
525  if((status & ENC28J60_RSV_RECEIVED_OK) != 0)
526  {
527  //Limit the number of data to read
529  //Read packet data
530  enc28j60ReadBuffer(interface, temp, length);
531 
532  //Valid packet received
533  error = NO_ERROR;
534  }
535  else
536  {
537  //The received packet contains an error
538  error = ERROR_INVALID_PACKET;
539  }
540 
541  //Advance the ERXRDPT pointer, taking care to wrap back at the end of the
542  //received memory buffer
543  if(context->nextPacket == ENC28J60_RX_BUFFER_START)
544  {
547  }
548  else
549  {
550  enc28j60WriteReg(interface, ENC28J60_ERXRDPTL, LSB(context->nextPacket - 1));
551  enc28j60WriteReg(interface, ENC28J60_ERXRDPTH, MSB(context->nextPacket - 1));
552  }
553 
554  //Decrement the packet counter
556  }
557  else
558  {
559  //No more data in the receive buffer
560  error = ERROR_BUFFER_EMPTY;
561  }
562 
563  //Check whether a valid packet has been received
564  if(!error)
565  {
566  NetRxAncillary ancillary;
567 
568  //Additional options can be passed to the stack along with the packet
569  ancillary = NET_DEFAULT_RX_ANCILLARY;
570 
571  //Pass the packet to the upper layer
572  nicProcessPacket(interface, temp, length, &ancillary);
573  }
574 
575  //Return status code
576  return error;
577 }
578 
579 
580 /**
581  * @brief Configure MAC address filtering
582  * @param[in] interface Underlying network interface
583  * @return Error code
584  **/
585 
587 {
588  uint_t i;
589  uint_t k;
590  uint32_t crc;
591  uint8_t hashTable[8];
592  MacFilterEntry *entry;
593 
594  //Debug message
595  TRACE_DEBUG("Updating MAC filter...\r\n");
596 
597  //Clear hash table
598  osMemset(hashTable, 0, sizeof(hashTable));
599 
600  //The MAC address filter contains the list of MAC addresses to accept
601  //when receiving an Ethernet frame
602  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
603  {
604  //Point to the current entry
605  entry = &interface->macAddrFilter[i];
606 
607  //Valid entry?
608  if(entry->refCount > 0)
609  {
610  //Compute CRC over the current MAC address
611  crc = enc28j60CalcCrc(&entry->addr, sizeof(MacAddr));
612  //Calculate the corresponding index in the table
613  k = (crc >> 23) & 0x3F;
614  //Update hash table contents
615  hashTable[k / 8] |= (1 << (k % 8));
616  }
617  }
618 
619  //Write the hash table to the ENC28J60 controller
620  enc28j60WriteReg(interface, ENC28J60_EHT0, hashTable[0]);
621  enc28j60WriteReg(interface, ENC28J60_EHT1, hashTable[1]);
622  enc28j60WriteReg(interface, ENC28J60_EHT2, hashTable[2]);
623  enc28j60WriteReg(interface, ENC28J60_EHT3, hashTable[3]);
624  enc28j60WriteReg(interface, ENC28J60_EHT4, hashTable[4]);
625  enc28j60WriteReg(interface, ENC28J60_EHT5, hashTable[5]);
626  enc28j60WriteReg(interface, ENC28J60_EHT6, hashTable[6]);
627  enc28j60WriteReg(interface, ENC28J60_EHT7, hashTable[7]);
628 
629  //Debug message
630  TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT0));
631  TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT1));
632  TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT2));
633  TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT3));
634  TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT4));
635  TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT5));
636  TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT6));
637  TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_EHT7));
638 
639  //Successful processing
640  return NO_ERROR;
641 }
642 
643 
644 /**
645  * @brief ENC28J60 controller reset
646  * @param[in] interface Underlying network interface
647  **/
648 
650 {
651  //Pull the CS pin low
652  interface->spiDriver->assertCs();
653 
654  //Write opcode
655  interface->spiDriver->transfer(ENC28J60_CMD_SRC);
656 
657  //Terminate the operation by raising the CS pin
658  interface->spiDriver->deassertCs();
659 }
660 
661 
662 /**
663  * @brief Bank selection
664  * @param[in] interface Underlying network interface
665  * @param[in] address Register address
666  **/
667 
668 void enc28j60SelectBank(NetInterface *interface, uint16_t address)
669 {
670  uint16_t bank;
671  Enc28j60Context *context;
672 
673  //Point to the driver context
674  context = (Enc28j60Context *) interface->nicContext;
675 
676  //Get the bank number from the specified address
677  bank = address & REG_BANK_MASK;
678 
679  //Rewrite the bank number only if a change is detected
680  if(bank != context->currentBank)
681  {
682  //Select the relevant bank
683  if(bank == BANK_0)
684  {
685  //Select bank 0
688  }
689  else if(bank == BANK_1)
690  {
691  //Select bank 1
694  }
695  else if(bank == BANK_2)
696  {
697  //Select bank 2
700  }
701  else
702  {
703  //Select bank 3
706  }
707 
708  //Save bank number
709  context->currentBank = bank;
710  }
711 }
712 
713 
714 /**
715  * @brief Write ENC28J60 register
716  * @param[in] interface Underlying network interface
717  * @param[in] address Register address
718  * @param[in] data Register value
719  **/
720 
721 void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data)
722 {
723  //Make sure the corresponding bank is selected
724  enc28j60SelectBank(interface, address);
725 
726  //Pull the CS pin low
727  interface->spiDriver->assertCs();
728 
729  //Write opcode and register address
730  interface->spiDriver->transfer(ENC28J60_CMD_WCR | (address & REG_ADDR_MASK));
731  //Write register value
732  interface->spiDriver->transfer(data);
733 
734  //Terminate the operation by raising the CS pin
735  interface->spiDriver->deassertCs();
736 }
737 
738 
739 /**
740  * @brief Read ENC28J60 register
741  * @param[in] interface Underlying network interface
742  * @param[in] address Register address
743  * @return Register value
744  **/
745 
746 uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address)
747 {
748  uint16_t data;
749 
750  //Make sure the corresponding bank is selected
751  enc28j60SelectBank(interface, address);
752 
753  //Pull the CS pin low
754  interface->spiDriver->assertCs();
755 
756  //Write opcode and register address
757  interface->spiDriver->transfer(ENC28J60_CMD_RCR | (address & REG_ADDR_MASK));
758 
759  //When reading MAC or MII registers, a dummy byte is first shifted out
761  {
762  interface->spiDriver->transfer(0x00);
763  }
764 
765  //Read register contents
766  data = interface->spiDriver->transfer(0x00);
767 
768  //Terminate the operation by raising the CS pin
769  interface->spiDriver->deassertCs();
770 
771  //Return register contents
772  return data;
773 }
774 
775 
776 /**
777  * @brief Write PHY register
778  * @param[in] interface Underlying network interface
779  * @param[in] address PHY register address
780  * @param[in] data Register value
781  **/
782 
783 void enc28j60WritePhyReg(NetInterface *interface, uint16_t address,
784  uint16_t data)
785 {
786  //Write register address
788 
789  //Write the lower 8 bits
790  enc28j60WriteReg(interface, ENC28J60_MIWRL, LSB(data));
791  //Write the upper 8 bits
792  enc28j60WriteReg(interface, ENC28J60_MIWRH, MSB(data));
793 
794  //Wait until the PHY register has been written
795  while((enc28j60ReadReg(interface, ENC28J60_MISTAT) & ENC28J60_MISTAT_BUSY) != 0)
796  {
797  }
798 }
799 
800 
801 /**
802  * @brief Read PHY register
803  * @param[in] interface Underlying network interface
804  * @param[in] address PHY register address
805  * @return Register value
806  **/
807 
808 uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address)
809 {
810  uint16_t data;
811 
812  //Write register address
814 
815  //Start read operation
817  //Wait for the read operation to complete
818  while((enc28j60ReadReg(interface, ENC28J60_MISTAT) & ENC28J60_MISTAT_BUSY) != 0)
819  {
820  }
821 
822  //Clear command register
823  enc28j60WriteReg(interface, ENC28J60_MICMD, 0);
824 
825  //Read the lower 8 bits
826  data = enc28j60ReadReg(interface, ENC28J60_MIRDL);
827  //Read the upper 8 bits
828  data |= enc28j60ReadReg(interface, ENC28J60_MIRDH) << 8;
829 
830  //Return register contents
831  return data;
832 }
833 
834 
835 /**
836  * @brief Write SRAM buffer
837  * @param[in] interface Underlying network interface
838  * @param[in] buffer Multi-part buffer containing the data to be written
839  * @param[in] offset Offset to the first data byte
840  **/
841 
843  const NetBuffer *buffer, size_t offset)
844 {
845  uint_t i;
846  size_t j;
847  size_t n;
848  uint8_t *p;
849 
850  //Pull the CS pin low
851  interface->spiDriver->assertCs();
852 
853  //Write opcode
854  interface->spiDriver->transfer(ENC28J60_CMD_WBM);
855  //Write per-packet control byte
856  interface->spiDriver->transfer(0x00);
857 
858  //Loop through data chunks
859  for(i = 0; i < buffer->chunkCount; i++)
860  {
861  //Is there any data to copy from the current chunk?
862  if(offset < buffer->chunk[i].length)
863  {
864  //Point to the first byte to be read
865  p = (uint8_t *) buffer->chunk[i].address + offset;
866  //Compute the number of bytes to copy at a time
867  n = buffer->chunk[i].length - offset;
868 
869  //Copy data to SRAM buffer
870  for(j = 0; j < n; j++)
871  {
872  interface->spiDriver->transfer(p[j]);
873  }
874 
875  //Process the next block from the start
876  offset = 0;
877  }
878  else
879  {
880  //Skip the current chunk
881  offset -= buffer->chunk[i].length;
882  }
883  }
884 
885  //Terminate the operation by raising the CS pin
886  interface->spiDriver->deassertCs();
887 }
888 
889 
890 /**
891  * @brief Read SRAM buffer
892  * @param[in] interface Underlying network interface
893  * @param[out] data Buffer where to store the incoming data
894  * @param[in] length Number of data to read
895  **/
896 
898  uint8_t *data, size_t length)
899 {
900  size_t i;
901 
902  //Pull the CS pin low
903  interface->spiDriver->assertCs();
904 
905  //Write opcode
906  interface->spiDriver->transfer(ENC28J60_CMD_RBM);
907 
908  //Copy data from SRAM buffer
909  for(i = 0; i < length; i++)
910  {
911  data[i] = interface->spiDriver->transfer(0x00);
912  }
913 
914  //Terminate the operation by raising the CS pin
915  interface->spiDriver->deassertCs();
916 }
917 
918 
919 /**
920  * @brief Set bit field
921  * @param[in] interface Underlying network interface
922  * @param[in] address Register address
923  * @param[in] mask Bits to set in the target register
924  **/
925 
926 void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask)
927 {
928  //Pull the CS pin low
929  interface->spiDriver->assertCs();
930 
931  //Write opcode and register address
932  interface->spiDriver->transfer(ENC28J60_CMD_BFS | (address & REG_ADDR_MASK));
933  //Write bit mask
934  interface->spiDriver->transfer(mask);
935 
936  //Terminate the operation by raising the CS pin
937  interface->spiDriver->deassertCs();
938 }
939 
940 
941 /**
942  * @brief Clear bit field
943  * @param[in] interface Underlying network interface
944  * @param[in] address Register address
945  * @param[in] mask Bits to clear in the target register
946  **/
947 
948 void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask)
949 {
950  //Pull the CS pin low
951  interface->spiDriver->assertCs();
952 
953  //Write opcode and register address
954  interface->spiDriver->transfer(ENC28J60_CMD_BFC | (address & REG_ADDR_MASK));
955  //Write bit mask
956  interface->spiDriver->transfer(mask);
957 
958  //Terminate the operation by raising the CS pin
959  interface->spiDriver->deassertCs();
960 }
961 
962 
963 /**
964  * @brief CRC calculation using the polynomial 0x4C11DB7
965  * @param[in] data Pointer to the data over which to calculate the CRC
966  * @param[in] length Number of bytes to process
967  * @return Resulting CRC value
968  **/
969 
970 uint32_t enc28j60CalcCrc(const void *data, size_t length)
971 {
972  uint_t i;
973  uint_t j;
974  uint32_t crc;
975  const uint8_t *p;
976 
977  //Point to the data over which to calculate the CRC
978  p = (uint8_t *) data;
979  //CRC preset value
980  crc = 0xFFFFFFFF;
981 
982  //Loop through data
983  for(i = 0; i < length; i++)
984  {
985  //The message is processed bit by bit
986  for(j = 0; j < 8; j++)
987  {
988  //Update CRC value
989  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
990  {
991  crc = (crc << 1) ^ 0x04C11DB7;
992  }
993  else
994  {
995  crc = crc << 1;
996  }
997  }
998  }
999 
1000  //Return CRC value
1001  return crc;
1002 }
1003 
1004 
1005 /**
1006  * @brief Dump registers for debugging purpose
1007  * @param[in] interface Underlying network interface
1008  **/
1009 
1011 {
1012 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
1013  uint8_t i;
1014  uint8_t bank;
1015  uint16_t address;
1016 
1017  //Display header
1018  TRACE_DEBUG(" Bank 0 Bank 1 Bank 2 Bank 3\r\n");
1019 
1020  //Loop through register addresses
1021  for(i = 0; i < 32; i++)
1022  {
1023  //Display register address
1024  TRACE_DEBUG("%02" PRIX8 ": ", i);
1025 
1026  //Loop through bank numbers
1027  for(bank = 0; bank < 4; bank++)
1028  {
1029  //Format register address
1030  address = (bank << 8) | i;
1031 
1032  //MAC and MII registers require a specific read sequence
1033  if(address >= 0x200 && address <= 0x219)
1034  {
1035  address |= MAC_REG_TYPE;
1036  }
1037  else if(address >= 0x300 && address <= 0x305)
1038  {
1039  address |= MAC_REG_TYPE;
1040  }
1041  else if(address == 0x30A)
1042  {
1043  address |= MAC_REG_TYPE;
1044  }
1045 
1046  //Display register contents
1047  TRACE_DEBUG("0x%02" PRIX8 " ", enc28j60ReadReg(interface, address));
1048  }
1049 
1050  //Jump to the following line
1051  TRACE_DEBUG("\r\n");
1052  }
1053 
1054  //Terminate with a line feed
1055  TRACE_DEBUG("\r\n");
1056 #endif
1057 }
1058 
1059 
1060 /**
1061  * @brief Dump PHY registers for debugging purpose
1062  * @param[in] interface Underlying network interface
1063  **/
1064 
1066 {
1067 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
1068  uint8_t i;
1069 
1070  //Loop through PHY registers
1071  for(i = 0; i < 32; i++)
1072  {
1073  //Display current PHY register
1074  TRACE_DEBUG("%02" PRIX8 ": 0x%04" PRIX16 "\r\n", i,
1075  enc28j60ReadPhyReg(interface, i));
1076  }
1077 
1078  //Terminate with a line feed
1079  TRACE_DEBUG("\r\n");
1080 #endif
1081 }
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
#define LOAD16LE(p)
Definition: cpu_endian.h:181
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask)
Set bit field.
void enc28j60DumpReg(NetInterface *interface)
Dump registers for debugging purpose.
const NicDriver enc28j60Driver
ENC28J60 driver.
uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address)
Read ENC28J60 register.
void enc28j60SoftReset(NetInterface *interface)
ENC28J60 controller reset.
void enc28j60DisableIrq(NetInterface *interface)
Disable interrupts.
bool_t enc28j60IrqHandler(NetInterface *interface)
ENC28J60 interrupt service routine.
error_t enc28j60SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data)
Write ENC28J60 register.
void enc28j60ReadBuffer(NetInterface *interface, uint8_t *data, size_t length)
Read SRAM buffer.
void enc28j60EnableIrq(NetInterface *interface)
Enable interrupts.
uint32_t enc28j60CalcCrc(const void *data, size_t length)
CRC calculation using the polynomial 0x4C11DB7.
void enc28j60Tick(NetInterface *interface)
ENC28J60 timer handler.
void enc28j60EventHandler(NetInterface *interface)
ENC28J60 event handler.
void enc28j60WriteBuffer(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Write SRAM buffer.
void enc28j60SelectBank(NetInterface *interface, uint16_t address)
Bank selection.
void enc28j60DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
error_t enc28j60ReceivePacket(NetInterface *interface)
Receive a packet.
error_t enc28j60UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask)
Clear bit field.
void enc28j60WritePhyReg(NetInterface *interface, uint16_t address, uint16_t data)
Write PHY register.
error_t enc28j60Init(NetInterface *interface)
ENC28J60 controller initialization.
__weak_func void enc28j60InitHook(NetInterface *interface)
ENC28J60 custom configuration.
uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address)
Read PHY register.
ENC28J60 Ethernet controller.
#define ENC28J60_CMD_SRC
#define ENC28J60_EHT5
#define ENC28J60_ECOCON
#define ENC28J60_ERXRDPTL
#define ENC28J60_PHCON2
#define ENC28J60_CMD_WCR
#define ENC28J60_PHCON1_PDPXMD
#define ENC28J60_ETXSTL
#define ENC28J60_EIR_PKTIF
#define REG_BANK_MASK
#define ENC28J60_PHIE_PLNKIE
#define ENC28J60_MABBIPG_DEFAULT_FD
#define ENC28J60_MAADR1
#define ENC28J60_MAADR5
#define ENC28J60_PHIR
#define BANK_0
#define ENC28J60_CMD_BFC
#define ENC28J60_MAADR4
#define ENC28J60_MAIPGL_DEFAULT
#define ENC28J60_EHT7
#define REG_TYPE_MASK
#define ENC28J60_RSV_RECEIVED_OK
#define ENC28J60_RX_BUFFER_STOP
#define ENC28J60_MACON3_FRMLNEN
#define ENC28J60_MICMD
#define ENC28J60_ERXFCON_BCEN
#define ENC28J60_PHCON1
#define ENC28J60_CMD_RCR
#define ENC28J60_ERXNDH
#define ENC28J60_MACON3_PADCFG_AUTO
#define ENC28J60_ERXFCON
#define ENC28J60_MABBIPG_DEFAULT_HD
#define MAC_REG_TYPE
#define ENC28J60_ECON1_TXRST
#define ENC28J60_PHSTAT2_LSTAT
#define ENC28J60_EIR_LINKIF
#define ENC28J60_CMD_RBM
#define ENC28J60_MACON4_DEFER
#define ENC28J60_MAADR2
#define ENC28J60_EIE_PKTIE
#define ENC28J60_ETXSTH
#define ENC28J60_PHSTAT2
#define ENC28J60_MACON1_TXPAUS
#define ENC28J60_EHT1
#define ENC28J60_ERXFCON_HTEN
#define ENC28J60_MACON3_FULDPX
#define ENC28J60_EHT4
#define ENC28J60_MISTAT_BUSY
#define ENC28J60_MIWRL
#define ENC28J60_EHT0
#define ENC28J60_ERXRDPTH
#define ENC28J60_MACON2
#define ETH_REG_TYPE
#define ENC28J60_TX_BUFFER_START
#define ENC28J60_ECON1
#define ENC28J60_ECON1_RXEN
#define ENC28J60_MISTAT
#define ENC28J60_MIWRH
#define ENC28J60_MACON4
#define BANK_1
#define ENC28J60_MAADR3
#define ENC28J60_MAADR0
#define ENC28J60_ERXFCON_UCEN
#define ENC28J60_MABBIPG
#define ENC28J60_CMD_WBM
#define ENC28J60_MACON3
#define ENC28J60_EIE_INTIE
#define ENC28J60_PHLCON_LFRQ_40_MS
#define ENC28J60_MAIPGL
#define ENC28J60_ERXSTL
#define ENC28J60_EIR
#define ENC28J60_EIR_TXERIF
#define ENC28J60_PHIE
#define ENC28J60_ECON1_TXRTS
#define ENC28J60_EHT2
#define ENC28J60_PHCON2_HDLDIS
#define ENC28J60_ECON1_BSEL0
#define BANK_2
#define ENC28J60_CMD_BFS
#define ENC28J60_ETXNDL
#define ENC28J60_ERDPTL
#define ENC28J60_MACLCON2
#define ENC28J60_MACLCON2_COLWIN_DEFAULT
#define ENC28J60_MACON1_MARXEN
#define ENC28J60_ETH_RX_BUFFER_SIZE
#define ENC28J60_ERXFCON_CRCEN
#define ENC28J60_ERDPTH
#define ENC28J60_MACON3_TXCRCEN
#define ENC28J60_EIE
#define ENC28J60_MAIPGH
#define ENC28J60_EHT3
#define ENC28J60_ECON1_BSEL1
#define ENC28J60_ERXSTH
#define ENC28J60_MAMXFLL
#define ENC28J60_EREVID
#define ENC28J60_PHLCON_STRCH
#define ENC28J60_MAIPGH_DEFAULT
#define ENC28J60_PHIE_PGEIE
#define ENC28J60_ETXNDH
#define ENC28J60_EIR_TXIF
#define ENC28J60_PHLCON_LBCFG_TX_RX
#define ENC28J60_MIRDL
#define ENC28J60_MACON1_RXPAUS
#define ENC28J60_PHLCON_LACFG_LINK
#define ENC28J60_EPKTCNT
#define ENC28J60_ECON2
#define ENC28J60_EWRPTH
#define ENC28J60_EHT6
#define ENC28J60_MIREGADR
#define ENC28J60_EIE_LINKIE
#define ENC28J60_ECON2_PKTDEC
#define ENC28J60_MIRDH
#define ENC28J60_EIE_TXERIE
#define ENC28J60_PHLCON
#define ENC28J60_MICMD_MIIRD
#define ENC28J60_RX_BUFFER_START
#define ENC28J60_MACON1
#define REG_ADDR_MASK
#define ENC28J60_ECOCON_COCON_DISABLED
#define ENC28J60_EWRPTL
#define ENC28J60_EIE_TXIE
#define ENC28J60_ERXNDL
#define ENC28J60_MAMXFLH
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
Ipv6Addr address[]
Definition: ipv6.h:316
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define osMemset(p, value, length)
Definition: os_port.h:135
#define LSB(x)
Definition: os_port.h:55
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define MSB(x)
Definition: os_port.h:59
#define sleep(delay)
Definition: os_port.h:301
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
uint16_t length
Definition: net_mem.h:79
void * address
Definition: net_mem.h:78
ENC28J60 driver context.
uint16_t nextPacket
Next packet in the receive buffer.
uint16_t currentBank
Current bank.
MAC filter table entry.
Definition: ethernet.h:262
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint_t chunkCount
Definition: net_mem.h:90
ChunkDesc chunk[]
Definition: net_mem.h:92
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369
uint8_t mask
Definition: web_socket.h:319