Skip to content

Commit 6e0d1fa

Browse files
committed
init
0 parents  commit 6e0d1fa

File tree

8 files changed

+2267
-0
lines changed

8 files changed

+2267
-0
lines changed

LICENSE

+504
Large diffs are not rendered by default.

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Mbed OS Ethernet MAC driver for the W5500
2+
3+
This Arduino library uses [W5500 driver](https://github.com/njh/W5500MacRaw) by Nicholas Humfrey with some adaptation.
4+
5+
Arduino Giga should work with Arduino Ethernet 2 shield. Arduino Portenta H7 boards should work with MKR ETH shield.
6+
7+
If you use a nodule with W5500, wire it to standard SPI pins of the board. On Nano pins 10 to 13. On Portenta pins 7 to 10. On Giga R1 use the SPI header and pin 10 as CS.
8+
9+
For Arduino Giga R1, the Ethernet library has to be copied from Mbed Portenta boards package. For Mbed Core Nano boards and RP2040 boards, Ethernet and SocketWrapper library have to be copied.
10+
11+
To use the driver include it in the sketch with the Portenta Ethernet library:
12+
13+
```
14+
#include <W5500EMAC.h>
15+
#include <PortentaEthernet.h>
16+
``````

examples/WebServer/WebServer.ino

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Web Server
3+
4+
A simple web server that shows the value of the analog input pins.
5+
6+
created 18 Dec 2009
7+
by David A. Mellis
8+
modified 9 Apr 2012
9+
by Tom Igoe
10+
modified 02 Sept 2015
11+
by Arturo Guadalupi
12+
13+
*/
14+
15+
#include <W5500EMAC.h>
16+
#include <PortentaEthernet.h>
17+
18+
// The IP address will be dependent on your local network:
19+
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
20+
21+
// Initialize the Ethernet server library
22+
// with the IP address and port you want to use
23+
// (port 80 is default for HTTP):
24+
EthernetServer server(80);
25+
26+
void setup() {
27+
28+
// Open serial communications and wait for port to open:
29+
Serial.begin(115200);
30+
while (!Serial) {
31+
; // wait for serial port to connect. Needed for native USB port only
32+
}
33+
Serial.println("Ethernet WebServer Example");
34+
35+
// start the Ethernet connection and the server:
36+
Ethernet.begin(mac);
37+
38+
// Check for Ethernet hardware present
39+
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
40+
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
41+
while (true) {
42+
delay(1); // do nothing, no point running without Ethernet hardware
43+
}
44+
}
45+
if (Ethernet.linkStatus() == LinkOFF) {
46+
Serial.println("Ethernet cable is not connected.");
47+
}
48+
49+
// start the server
50+
server.begin();
51+
Serial.print("server is at ");
52+
Serial.println(Ethernet.localIP());
53+
}
54+
55+
56+
void loop() {
57+
58+
// listen for incoming clients
59+
EthernetClient client = server.available();
60+
if (client) {
61+
Serial.println("new client");
62+
// an http request ends with a blank line
63+
boolean currentLineIsBlank = true;
64+
while (client.connected()) {
65+
if (client.available()) {
66+
char c = client.read();
67+
Serial.write(c);
68+
// if you've gotten to the end of the line (received a newline
69+
// character) and the line is blank, the http request has ended,
70+
// so you can send a reply
71+
if (c == '\n' && currentLineIsBlank) {
72+
// send a standard http response header
73+
client.println("HTTP/1.1 200 OK");
74+
client.println("Content-Type: text/html");
75+
client.println("Connection: close"); // the connection will be closed after completion of the response
76+
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
77+
client.println();
78+
client.println("<!DOCTYPE HTML>");
79+
client.println("<html>");
80+
// output the value of each analog input pin
81+
for (int analogChannel = 0; analogChannel < 4; analogChannel++) {
82+
int sensorReading = analogRead(analogChannel);
83+
client.print("analog input ");
84+
client.print(analogChannel);
85+
client.print(" is ");
86+
client.print(sensorReading);
87+
client.println("<br />");
88+
}
89+
client.println("</html>");
90+
client.flush();
91+
break;
92+
}
93+
if (c == '\n') {
94+
// you're starting a new line
95+
currentLineIsBlank = true;
96+
} else if (c != '\r') {
97+
// you've gotten a character on the current line
98+
currentLineIsBlank = false;
99+
}
100+
}
101+
}
102+
// give the web browser time to receive the data
103+
delay(1);
104+
// close the connection:
105+
client.stop();
106+
Serial.println("client disconnected");
107+
}
108+
}

library.properties

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=W5500-EMAC
2+
version=1.0.0
3+
author=Juraj Andrassy
4+
maintainer=Juraj Andrassy <[email protected]>
5+
sentence=W5500 Mbed EMAC for Arduino Mbed Core boards
6+
paragraph=Use a W5500 Ethernet shield or a module with Arduino Mbed Core Ethernet library.
7+
category=Communication
8+
url=https://github.com/Networking-for-Arduino/W5500-EMAC
9+
architectures=mbed
10+
includes=W5500EMAC.h
11+
dot_a_linkage=true

src/W5500EMAC.cpp

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
#include "W5500EMAC.h"
2+
#include <Arduino.h>
3+
#include <SPI.h>
4+
5+
#ifndef W5500_CS
6+
#define W5500_CS PIN_SPI_SS
7+
#endif
8+
9+
#define W5500_BUFF_ALIGNMENT 4U
10+
#define W5500_ETH_MTU_SIZE 1500U
11+
#define W5500_ETH_IF_NAME "W5500"
12+
13+
using namespace mbed;
14+
using namespace rtos;
15+
using namespace std::chrono_literals;
16+
17+
#define W5500_RECEIVE_TASK_PERIOD_MS 20ms
18+
#define W5500_LINK_STATUS_TASK_PERIOD_MS 500ms
19+
20+
#define SPI_ETHERNET_SETTINGS SPISettings(20000000, MSBFIRST, SPI_MODE0)
21+
22+
W5500EMAC::W5500EMAC(SPIClass &_spi) : spi(_spi), driver(W5500_CS, _spi) {
23+
}
24+
25+
W5500EMAC& W5500EMAC::get_instance(void) {
26+
static W5500EMAC emac;
27+
return emac;
28+
}
29+
30+
/**
31+
* Return maximum transmission unit
32+
*
33+
* @return MTU in bytes
34+
*/
35+
uint32_t W5500EMAC::get_mtu_size(void) const {
36+
return W5500_ETH_MTU_SIZE;
37+
}
38+
39+
/**
40+
* Gets memory buffer alignment preference
41+
*
42+
* Gets preferred memory buffer alignment of the Emac device. IP stack may
43+
* or may not align link out memory buffer chains using the alignment.
44+
*
45+
* @return Memory alignment requirement in bytes
46+
*/
47+
uint32_t W5500EMAC::get_align_preference(void) const {
48+
return W5500_BUFF_ALIGNMENT;
49+
}
50+
51+
/**
52+
* Return interface name
53+
*
54+
* @param name Pointer to where the name should be written
55+
* @param size Maximum number of character to copy
56+
*/
57+
void W5500EMAC::get_ifname(char *name, uint8_t size) const {
58+
memcpy(name, W5500_ETH_IF_NAME, (size < sizeof(W5500_ETH_IF_NAME)) ? size : sizeof(W5500_ETH_IF_NAME));
59+
}
60+
61+
/**
62+
* Returns size of the underlying interface HW address size.
63+
*
64+
* @return HW address size in bytes
65+
*/
66+
uint8_t W5500EMAC::get_hwaddr_size(void) const {
67+
return W5500_HWADDR_SIZE;
68+
}
69+
70+
/**
71+
* Return interface-supplied HW address
72+
*
73+
* Copies HW address to provided memory, @param addr has to be of correct
74+
* size see @a get_hwaddr_size
75+
*
76+
* HW address need not be provided if this interface does not have its own
77+
* HW address configuration; stack will choose address from central system
78+
* configuration if the function returns false and does not write to addr.
79+
*
80+
* @param addr HW address for underlying interface
81+
* @return true if HW address is available
82+
*/
83+
bool W5500EMAC::get_hwaddr(uint8_t *addr) const {
84+
memcpy(addr, macAddr, W5500_HWADDR_SIZE);
85+
return true;
86+
}
87+
88+
/**
89+
* Set HW address for interface
90+
*
91+
* Provided address has to be of correct size, see @a get_hwaddr_size
92+
*
93+
* Called to set the MAC address to actually use - if @a get_hwaddr is
94+
* provided the stack would normally use that, but it could be overridden,
95+
* eg for test purposes.
96+
*
97+
* @param addr Address to be set
98+
*/
99+
void W5500EMAC::set_hwaddr(const uint8_t *addr) {
100+
memcpy(macAddr, addr, W5500_HWADDR_SIZE);
101+
}
102+
103+
/**
104+
* Initializes the HW
105+
*
106+
* @return True on success, False in case of an error.
107+
*/
108+
bool W5500EMAC::power_up(void) {
109+
110+
spi.begin();
111+
spi.beginTransaction(SPI_ETHERNET_SETTINGS);
112+
bool ret = driver.begin(macAddr);
113+
spi.endTransaction();
114+
if (!ret)
115+
return false;
116+
receiveTaskHandle = mbed::mbed_event_queue()->call_every(W5500_RECEIVE_TASK_PERIOD_MS, mbed::callback(this, &W5500EMAC::receiveTask));
117+
linkStatusTaskHandle = mbed::mbed_event_queue()->call_every(W5500_LINK_STATUS_TASK_PERIOD_MS, mbed::callback(this, &W5500EMAC::linkStatusTask));
118+
return true;
119+
}
120+
121+
/**
122+
* Deinitializes the HW
123+
*
124+
*/
125+
void W5500EMAC::power_down(void) {
126+
mbed::mbed_event_queue()->cancel(receiveTaskHandle);
127+
mbed::mbed_event_queue()->cancel(linkStatusTaskHandle);
128+
driver.end();
129+
}
130+
131+
/**
132+
* Sends the packet over the link
133+
*
134+
* That can not be called from an interrupt context.
135+
*
136+
* @param buf Packet to be send
137+
* @return True if the packet was send successfully, False otherwise
138+
*/
139+
bool W5500EMAC::link_out(emac_mem_buf_t *buf) {
140+
141+
if (buf == NULL)
142+
return false;
143+
144+
// If buffer is chained or not aligned then make a contiguous aligned copy of it
145+
if (memoryManager->get_next(buf) || reinterpret_cast<uint32_t>(memoryManager->get_ptr(buf)) % W5500_BUFF_ALIGNMENT) {
146+
emac_mem_buf_t *copy_buf;
147+
copy_buf = memoryManager->alloc_heap(memoryManager->get_total_len(buf), W5500_BUFF_ALIGNMENT);
148+
if (NULL == copy_buf) {
149+
memoryManager->free(buf);
150+
return false;
151+
}
152+
153+
// Copy to new buffer and free original
154+
memoryManager->copy(copy_buf, buf);
155+
memoryManager->free(buf);
156+
buf = copy_buf;
157+
}
158+
159+
uint16_t len = memoryManager->get_len(buf);
160+
uint8_t *data = (uint8_t*) (memoryManager->get_ptr(buf));
161+
spi.beginTransaction(SPI_ETHERNET_SETTINGS);
162+
bool ret = driver.sendFrame(data, len) == len;
163+
spi.endTransaction();
164+
memoryManager->free(buf);
165+
166+
return ret;
167+
}
168+
169+
void W5500EMAC::linkStatusTask() {
170+
spi.beginTransaction(SPI_ETHERNET_SETTINGS);
171+
static bool linked = false;
172+
if (linked != driver.isLinked()) {
173+
linked = driver.isLinked();
174+
emac_link_state_cb(linked);
175+
}
176+
spi.endTransaction();
177+
}
178+
179+
void W5500EMAC::receiveTask() {
180+
if (!emac_link_input_cb)
181+
return;
182+
spi.beginTransaction(SPI_ETHERNET_SETTINGS);
183+
emac_mem_buf_t *buf = driver.readFrame(memoryManager);
184+
spi.endTransaction();
185+
if (buf != NULL) {
186+
emac_link_input_cb(buf);
187+
}
188+
}
189+
190+
/**
191+
* Sets a callback that needs to be called for packets received for that
192+
* interface
193+
*
194+
* @param input_cb Function to be register as a callback
195+
*/
196+
void W5500EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) {
197+
emac_link_input_cb = input_cb;
198+
}
199+
200+
/**
201+
* Sets a callback that needs to be called on link status changes for given
202+
* interface
203+
*
204+
* @param state_cb Function to be register as a callback
205+
*/
206+
void W5500EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) {
207+
emac_link_state_cb = state_cb;
208+
}
209+
210+
/** Add device to a multicast group
211+
*
212+
* @param address A multicast group hardware address
213+
*/
214+
void W5500EMAC::add_multicast_group(const uint8_t *address) {
215+
216+
}
217+
218+
/** Remove device from a multicast group
219+
*
220+
* @param address A multicast group hardware address
221+
*/
222+
void W5500EMAC::remove_multicast_group(const uint8_t *address) {
223+
224+
}
225+
226+
/** Request reception of all multicast packets
227+
*
228+
* @param all True to receive all multicasts
229+
* False to receive only multicasts addressed to specified groups
230+
*/
231+
void W5500EMAC::set_all_multicast(bool all) {
232+
233+
}
234+
235+
/** Sets memory manager that is used to handle memory buffers
236+
*
237+
* @param mem_mngr Pointer to memory manager
238+
*/
239+
void W5500EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) {
240+
memoryManager = &mem_mngr;
241+
}
242+
243+
EMAC& EMAC::get_default_instance() {
244+
return W5500EMAC::get_instance();
245+
}

0 commit comments

Comments
 (0)