lm3s_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file lm3s_eth_driver.c
3  * @brief Luminary Stellaris LM3S 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 //LM3S6965 device?
33 #if defined(LM3S6965)
34  #include "lm3s6965.h"
35 //LM3S9B92 device?
36 #elif defined(LM3S9B92)
37  #include "lm3s9b92.h"
38 #endif
39 
40 //Dependencies
41 #include "inc/hw_ints.h"
42 #include "inc/hw_memmap.h"
43 #include "inc/hw_types.h"
44 #include "driverlib/gpio.h"
45 #include "driverlib/interrupt.h"
46 #include "driverlib/sysctl.h"
47 #include "core/net.h"
49 #include "debug.h"
50 
51 //Underlying network interface
52 static NetInterface *nicDriverInterface;
53 
54 //IAR EWARM compiler?
55 #if defined(__ICCARM__)
56 
57 //Transmit buffer
58 #pragma data_alignment = 4
59 static uint8_t txBuffer[ETH_MAX_FRAME_SIZE + 2];
60 //Receive buffer
61 #pragma data_alignment = 4
62 static uint8_t rxBuffer[ETH_MAX_FRAME_SIZE];
63 
64 //Keil MDK-ARM or GCC compiler?
65 #else
66 
67 //Transmit buffer
68 static uint8_t txBuffer[ETH_MAX_FRAME_SIZE + 2] __attribute__((aligned(4)));
69 //Receive buffer
70 static uint8_t rxBuffer[ETH_MAX_FRAME_SIZE] __attribute__((aligned(4)));
71 
72 #endif
73 
74 
75 /**
76  * @brief Stellaris LM3S Ethernet driver
77  **/
78 
80 {
82  ETH_MTU,
90  NULL,
91  NULL,
92  NULL,
93  TRUE,
94  TRUE,
95  TRUE,
96  FALSE
97 };
98 
99 
100 /**
101  * @brief Stellaris LM3S Ethernet controller initialization
102  * @param[in] interface Underlying network interface
103  * @return Error code
104  **/
105 
107 {
108  uint_t div;
109 
110  //Debug message
111  TRACE_INFO("Initializing Stellaris LM3S Ethernet controller...\r\n");
112 
113  //Save underlying network interface
114  nicDriverInterface = interface;
115 
116  //Enable Ethernet controller clock
117  SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
118  //Reset Ethernet controller
119  SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
120 
121  //GPIO configuration
122  lm3sEthInitGpio(interface);
123 
124  //The MDC clock frequency cannot exceed 2.5MHz
125  div = SysCtlClockGet() / (2 * 2500000) - 1;
126  //Adjust MDC clock frequency
127  MAC_MDV_R = div & MAC_MDV_DIV_M;
128 
129  //Reset PHY transceiver
130  lm3sEthWritePhyReg(PHY_MR0, PHY_MR0_RESET);
131  //Wait for the reset to complete
132  while(lm3sEthReadPhyReg(PHY_MR0) & PHY_MR0_RESET);
133 
134  //Dump PHY registers for debugging purpose
136 
137  //Configure LED0 and LED1
138  lm3sEthWritePhyReg(PHY_MR23, PHY_MR23_LED0_RXTX | PHY_MR23_LED1_LINK);
139 
140  //Set the MAC address
141  MAC_IA0_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
142  MAC_IA1_R = interface->macAddr.w[2];
143 
144  //Enable automatic CRC generation and packet padding
145  MAC_TCTL_R = MAC_TCTL_DUPLEX | MAC_TCTL_CRC | MAC_TCTL_PADEN;
146  //Flush the receive FIFO and enable CRC verification
147  MAC_RCTL_R = MAC_RCTL_RSTFIFO | MAC_RCTL_BADCRC;
148 
149  //Configure Ethernet interrupts
150  MAC_IM_R = MAC_IM_PHYINTM | MAC_IM_TXEMPM | MAC_IM_RXINTM;
151  //Configure PHY interrupts
152  lm3sEthWritePhyReg(PHY_MR17, PHY_MR17_LSCHG_IE);
153 
154  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
155  IntPriorityGroupingSet(LM3S_ETH_IRQ_PRIORITY_GROUPING);
156  //Configure Ethernet interrupt priority
157  IntPrioritySet(INT_ETH, LM3S_ETH_IRQ_PRIORITY);
158 
159  //Enable transmitter
160  MAC_TCTL_R |= MAC_TCTL_TXEN;
161  //Enable receiver
162  MAC_RCTL_R |= MAC_RCTL_RXEN;
163 
164  //Accept any packets from the upper layer
165  osSetEvent(&interface->nicTxEvent);
166 
167  //Successful initialization
168  return NO_ERROR;
169 }
170 
171 
172 //EK-LM3S6965 evaluation board?
173 #if defined(USE_EK_LM3S6965)
174 
175 /**
176  * @brief GPIO configuration
177  * @param[in] interface Underlying network interface
178  **/
179 
180 void lm3sEthInitGpio(NetInterface *interface)
181 {
182  //Enable GPIO clock
183  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
184 
185  //Configure status LEDs
186  GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3);
187 }
188 
189 #endif
190 
191 
192 /**
193  * @brief Stellaris LM3S Ethernet timer handler
194  *
195  * This routine is periodically called by the TCP/IP stack to
196  * handle periodic operations such as polling the link state
197  *
198  * @param[in] interface Underlying network interface
199  **/
200 
201 void lm3sEthTick(NetInterface *interface)
202 {
203 }
204 
205 
206 /**
207  * @brief Enable interrupts
208  * @param[in] interface Underlying network interface
209  **/
210 
212 {
213  //Enable Ethernet interrupts
214  IntEnable(INT_ETH);
215 }
216 
217 
218 /**
219  * @brief Disable interrupts
220  * @param[in] interface Underlying network interface
221  **/
222 
224 {
225  //Disable Ethernet interrupts
226  IntDisable(INT_ETH);
227 }
228 
229 
230 /**
231  * @brief Stellaris LM3S Ethernet interrupt service routine
232  **/
233 
234 void ETH_IRQHandler(void)
235 {
236  bool_t flag;
237  uint32_t status;
238 
239  //Enter interrupt service routine
240  osEnterIsr();
241 
242  //This flag will be set if a higher priority task must be woken
243  flag = FALSE;
244 
245  //Read interrupt status register
246  status = MAC_RIS_R;
247 
248  //PHY interrupt?
249  if(status & MAC_RIS_PHYINT)
250  {
251  //Disable PHYINT interrupt
252  MAC_IM_R &= ~MAC_IM_PHYINTM;
253 
254  //Set event flag
255  nicDriverInterface->nicEvent = TRUE;
256  //Notify the TCP/IP stack of the event
257  flag |= osSetEventFromIsr(&netEvent);
258  }
259 
260  //Transmit FIFO empty?
261  if(status & MAC_RIS_TXEMP)
262  {
263  //Acknowledge TXEMP interrupt
264  MAC_IACK_R = MAC_IACK_TXEMP;
265 
266  //Check whether the transmit FIFO is available for writing
267  if(!(MAC_TR_R & MAC_TR_NEWTX))
268  {
269  //Notify the TCP/IP stack that the transmitter is ready to send
270  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
271  }
272  }
273 
274  //Packet received?
275  if(status & MAC_RIS_RXINT)
276  {
277  //Disable RXINT interrupt
278  MAC_IM_R &= ~MAC_IM_RXINTM;
279 
280  //Set event flag
281  nicDriverInterface->nicEvent = TRUE;
282  //Notify the TCP/IP stack of the event
283  flag |= osSetEventFromIsr(&netEvent);
284  }
285 
286  //Leave interrupt service routine
287  osExitIsr(flag);
288 }
289 
290 
291 /**
292  * @brief Stellaris LM3S Ethernet event handler
293  * @param[in] interface Underlying network interface
294  **/
295 
297 {
298  uint32_t status;
299  uint16_t value;
300 
301  //Read interrupt status register
302  status = MAC_RIS_R;
303 
304  //PHY interrupt?
305  if(status & MAC_RIS_PHYINT)
306  {
307  //Acknowledge PHYINT interrupt
308  MAC_IACK_R = MAC_IACK_PHYINT;
309  //Read PHY interrupt status register
310  value = lm3sEthReadPhyReg(PHY_MR17);
311 
312  //Check whether the link state has changed
313  if(value & PHY_MR17_LSCHG_IE)
314  {
315  //Read PHY status register
316  value = lm3sEthReadPhyReg(PHY_MR1);
317 
318  //Check link state
319  if(value & PHY_MR1_LINK)
320  {
321  //Read PHY diagnostic register
322  value = lm3sEthReadPhyReg(PHY_MR18);
323 
324  //Get current speed
325  if(value & PHY_MR18_RATE)
326  {
327  //100BASE-TX operation
328  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
329  }
330  else
331  {
332  //10BASE-T operation
333  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
334  }
335 
336  //Get current duplex mode
337  if(value & PHY_MR18_DPLX)
338  {
339  //Full-Duplex mode
340  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
341  //Update MAC configuration
342  MAC_TCTL_R |= MAC_TCTL_DUPLEX;
343  }
344  else
345  {
346  //Half-Duplex mode
347  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
348  //Update MAC configuration
349  MAC_TCTL_R &= ~MAC_TCTL_DUPLEX;
350  }
351 
352  //Update link state
353  interface->linkState = TRUE;
354  }
355  else
356  {
357  //Update link state
358  interface->linkState = FALSE;
359  }
360 
361  //Process link state change event
362  nicNotifyLinkChange(interface);
363  }
364  }
365 
366  //Packet received?
367  if(status & MAC_RIS_RXINT)
368  {
369  //Acknowledge RXINT interrupt
370  MAC_IACK_R = MAC_IACK_RXINT;
371 
372  //Process all the pending packets
373  while(MAC_NP_R & MAC_NP_NPR_M)
374  {
375  //Read incoming packet
376  lm3sEthReceivePacket(interface);
377  }
378  }
379 
380  //Re-enable Ethernet interrupts
381  MAC_IM_R = MAC_IM_PHYINTM | MAC_IM_TXEMPM | MAC_IM_RXINTM;
382 }
383 
384 
385 /**
386  * @brief Send a packet
387  * @param[in] interface Underlying network interface
388  * @param[in] buffer Multi-part buffer containing the data to send
389  * @param[in] offset Offset to the first data byte
390  * @return Error code
391  **/
392 
394  const NetBuffer *buffer, size_t offset)
395 {
396  size_t i;
397  size_t length;
398  uint32_t *p;
399 
400  //Retrieve the length of the packet
401  length = netBufferGetLength(buffer) - offset;
402 
403  //Check the frame length
404  if(length < sizeof(EthHeader) || length > ETH_MAX_FRAME_SIZE)
405  {
406  //The transmitter can accept another packet
407  osSetEvent(&interface->nicTxEvent);
408  //Report an error
409  return ERROR_INVALID_LENGTH;
410  }
411 
412  //Make sure the transmit FIFO is available for writing
413  if(MAC_TR_R & MAC_TR_NEWTX)
414  return ERROR_FAILURE;
415 
416  //Copy user data
417  netBufferRead(txBuffer + 2, buffer, offset, length);
418 
419  //The packet is preceded by a 16-bit length field
420  txBuffer[0] = LSB(length - sizeof(EthHeader));
421  txBuffer[1] = MSB(length - sizeof(EthHeader));
422 
423  //Point to the beginning of the packet
424  p = (uint32_t *) txBuffer;
425  //Compute the length of the packet in 32-bit words
426  length = (length + 5) / 4;
427 
428  //Copy packet to transmit FIFO
429  for(i = 0; i < length; i++)
430  MAC_DATA_R = p[i];
431 
432  //Start transmitting
433  MAC_TR_R = MAC_TR_NEWTX;
434 
435  //Data successfully written
436  return NO_ERROR;
437 }
438 
439 
440 /**
441  * @brief Receive a packet
442  * @return Error code
443  **/
444 
446 {
447  error_t error;
448  size_t i;
449  size_t n;
450  size_t length;
451  uint32_t data;
452  uint16_t *p;
453 
454  //Make sure the FIFO is not empty
455  if(MAC_NP_R & MAC_NP_NPR_M)
456  {
457  //Read the first word
458  data = MAC_DATA_R;
459  //Retrieve the total length of the packet
460  length = data & 0xFFFF;
461 
462  //Make sure the length field is valid
463  if(length > 2)
464  {
465  //Point to the beginning of the buffer
466  p = (uint16_t *) rxBuffer;
467 
468  //Retrieve the length of the frame
469  length -= 2;
470  //Limit the number of data to be read
472 
473  //Copy the first half word
474  if(n > 0)
475  *(p++) = (uint16_t) (data >> 16);
476 
477  //Copy data from receive FIFO
478  for(i = 2; i < n; i += 4)
479  {
480  //Read a 32-bit word from the FIFO
481  data = MAC_DATA_R;
482  //Write the 32-bit to the receive buffer
483  *(p++) = (uint16_t) data;
484  *(p++) = (uint16_t) (data >> 16);
485  }
486 
487  //Skip the remaining bytes
488  while(i < length)
489  {
490  //Read a 32-bit word from the FIFO
491  data = MAC_DATA_R;
492  //Increment byte counter
493  i += 4;
494  }
495 
496  //Valid packet received
497  error = NO_ERROR;
498  }
499  else
500  {
501  //Disable receiver
502  MAC_RCTL_R &= ~MAC_RCTL_RXEN;
503  //Flush the receive FIFO
504  MAC_RCTL_R |= MAC_RCTL_RSTFIFO;
505  //Re-enable receiver
506  MAC_RCTL_R |= MAC_RCTL_RXEN;
507 
508  //The packet is not valid
509  error = ERROR_INVALID_PACKET;
510  }
511  }
512  else
513  {
514  //No more data in the receive buffer
515  error = ERROR_BUFFER_EMPTY;
516  }
517 
518  //Check whether a valid packet has been received
519  if(!error)
520  {
521  //Pass the packet to the upper layer
522  nicProcessPacket(interface, rxBuffer, n);
523  }
524 
525  //Return status code
526  return error;
527 }
528 
529 
530 /**
531  * @brief Configure MAC address filtering
532  * @param[in] interface Underlying network interface
533  * @return Error code
534  **/
535 
537 {
538  uint_t i;
539  bool_t acceptMulticast;
540 
541  //This flag will be set if multicast addresses should be accepted
542  acceptMulticast = FALSE;
543 
544  //The MAC address filter contains the list of MAC addresses to accept
545  //when receiving an Ethernet frame
546  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
547  {
548  //Valid entry?
549  if(interface->macAddrFilter[i].refCount > 0)
550  {
551  //Accept multicast addresses
552  acceptMulticast = TRUE;
553  //We are done
554  break;
555  }
556  }
557 
558  //Enable the reception of multicast frames if necessary
559  if(acceptMulticast)
560  MAC_RCTL_R |= MAC_RCTL_AMUL;
561  else
562  MAC_RCTL_R &= ~MAC_RCTL_AMUL;
563 
564  //Successful processing
565  return NO_ERROR;
566 }
567 
568 
569 /**
570  * @brief Write PHY register
571  * @param[in] address PHY register address
572  * @param[in] data Register value
573  **/
574 
575 void lm3sEthWritePhyReg(uint8_t address, uint16_t data)
576 {
577  //Data to be written in the PHY register
578  MAC_MTXD_R = data & MAC_MTXD_MDTX_M;
579  //Start a write operation
580  MAC_MCTL_R = (address << 3) | MAC_MCTL_WRITE | MAC_MCTL_START;
581 
582  //Wait for the write to complete
583  while(MAC_MCTL_R & MAC_MCTL_START);
584 }
585 
586 
587 /**
588  * @brief Read PHY register
589  * @param[in] address PHY register address
590  * @return Register value
591  **/
592 
593 uint16_t lm3sEthReadPhyReg(uint8_t address)
594 {
595  //Start a read operation
596  MAC_MCTL_R = (address << 3) | MAC_MCTL_START;
597 
598  //Wait for the read to complete
599  while(MAC_MCTL_R & MAC_MCTL_START);
600 
601  //Return PHY register contents
602  return MAC_MRXD_R & MAC_MRXD_MDRX_M;
603 }
604 
605 
606 /**
607  * @brief Dump PHY registers for debugging purpose
608  **/
609 
611 {
612  uint8_t i;
613 
614  //Loop through PHY registers
615  for(i = 0; i < 32; i++)
616  {
617  //Display current PHY register
618  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, lm3sEthReadPhyReg(i));
619  }
620 
621  //Terminate with a line feed
622  TRACE_DEBUG("\r\n");
623 }
#define ETH_MAX_FRAME_SIZE
Definition: ethernet.h:80
__start_packed struct @114 EthHeader
Ethernet frame header.
#define MAC_TR_R
void nicNotifyLinkChange(NetInterface *interface)
Process link state change event.
Definition: nic.c:298
#define MAC_MTXD_R
#define MSB(x)
Definition: os_port.h:56
TCP/IP stack core.
void lm3sEthTick(NetInterface *interface)
Stellaris LM3S Ethernet timer handler.
Debugging facilities.
#define MAC_MDV_R
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
Generic error code.
Definition: error.h:43
#define MAC_TCTL_R
#define txBuffer
#define LSB(x)
Definition: os_port.h:52
#define MAC_MRXD_R
#define TRUE
Definition: os_port.h:48
void lm3sEthDumpPhyReg(void)
Dump PHY registers for debugging purpose.
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:65
#define MAC_MCTL_R
#define MAC_NP_R
#define MAC_IACK_R
void lm3sEthEnableIrq(NetInterface *interface)
Enable interrupts.
#define LM3S_ETH_IRQ_PRIORITY_GROUPING
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:670
void lm3sEthWritePhyReg(uint8_t address, uint16_t data)
Write PHY register.
Luminary Stellaris LM3S Ethernet controller.
#define MAC_IA0_R
NIC driver.
Definition: nic.h:161
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:86
#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.
const NicDriver lm3sEthDriver
Stellaris LM3S Ethernet driver.
#define TRACE_INFO(...)
Definition: debug.h:86
#define ETH_MTU
Definition: ethernet.h:82
Ethernet interface.
Definition: nic.h:69
Success.
Definition: error.h:42
error_t lm3sEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define rxBuffer
Ipv6Addr address
OsEvent netEvent
Definition: net.c:72
void nicProcessPacket(NetInterface *interface, void *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:239
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
error_t
Error codes.
Definition: error.h:40
error_t lm3sEthReceivePacket(NetInterface *interface)
Receive a packet.
unsigned int uint_t
Definition: compiler_port.h:43
#define LM3S_ETH_IRQ_PRIORITY
uint8_t data[]
Definition: dtls_misc.h:167
#define NetInterface
Definition: net.h:34
#define MAC_RIS_R
uint8_t value[]
Definition: dtls_misc.h:141
void ETH_IRQHandler(void)
Stellaris LM3S Ethernet interrupt service routine.
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
error_t lm3sEthInit(NetInterface *interface)
Stellaris LM3S Ethernet controller initialization.
uint16_t lm3sEthReadPhyReg(uint8_t address)
Read PHY register.
void lm3sEthEventHandler(NetInterface *interface)
Stellaris LM3S Ethernet event handler.
void lm3sEthInitGpio(NetInterface *interface)
#define osExitIsr(flag)
#define MAC_DATA_R
#define osEnterIsr()
#define MAC_IA1_R
uint8_t length
Definition: dtls_misc.h:140
uint8_t n
#define MAC_RCTL_R
#define FALSE
Definition: os_port.h:44
int bool_t
Definition: compiler_port.h:47
#define MAC_IM_R
#define TRACE_DEBUG(...)
Definition: debug.h:98
error_t lm3sEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
void lm3sEthDisableIrq(NetInterface *interface)
Disable interrupts.