Arduino - Ethernet
Ethernet shield
There are quite a few Ethernet shields out there, but the more official and common shield, and the standard Ethernet library, are based on the Wiznet W5100.
Most network-related processing is done on the shield, but talking to the shield (via SPI) may still take at least a few milliseconds - which can matter to you.
The Ethernet library also supports the newer W5200 and W5500 variants. These two speak faster SPI which means you can handle packets faster, have a little more packet RAM, and they're also a little cheaper.
The W5100 speaks SPI and the shield use pin 10, 11, 12, and 13 (the AVR's hardware SPI), and passes all of the pins through (including the SPI ones - but note the bus bug in the older variant).
There was an older design of that more official shield:
- has a non-functional SD slot (at least, not officially supported - some people have reported getting it to work.)
- seems to have a bug where it doesn't release the bus (MISO?), meaning you can't use other SPI devices.
- Not wired to work with the Mega variants out of the box, but can be made to without too much trouble.(verify)
The newer shield (now the one listed at [1])
- is marked "ETHShield SD" and "mega compatible" (the latter because it uses SPI over the ICSP header)
- Has a MAC address on a sticker on the back
- has a functional microSD slot (its slave select is on digital pin 4(verify)[2]. )
- seems to not have the bus bug the earlier one has (...since the microSD card also uses the SPI bus)
Both will work with the basic library - and various others will too.
Power
Datasheet mentions it typically dissipates approx ~140mA (183mA max) - at 3.3V. Can't be powered off.(verify)
RAM
The Wiznet chips have packet RAM (8KB of Tx and 8KB of Rx for the W5100, 16KB of Tx and 16KB of Rx for the W5200 and W5500).
On AVRs, receiving full packets into a buffer is going to push your RAM limits, so when you can, you may want to define a protocol that you can deal with in smaller chunks at a time. (you may want to do that with UDP anyway, because packets could arrive out of order)
For some reason the library defines e.g. a UDP_TX_PACKET_MAX_SIZE as 24 bytes, but this does not seem to be a limitation or internal buffer size(verify).
On libraries
IIRC older versions required you to configure a MAC and IP address manually (plus a gateway and subnet if you actually wanted it to route to the internet).
Later (version 1.0?(verify)) it supports DHCP by using Ethernet.begin(mac), plus maintain() and some further logic if you want it to do renews and rebinds.
You are limited to four socket connections (in+out total) because of the W5100 (eight on 5200 and 5500(verify)).
More on the basic ethernet library:
- Incoming connections on the Server are returned as Client instantiations.
- It seems that according to server.available(), a client is considered a client not when it connects, but only once it has something to say.
- Even if only want your arduino to write out, the client will still have to send data before available() will return it as a Client you can write to (one byte of dummy data is enough).(verify)
Surprisingly, the early versions supported only TCP, not UDP, even though UDP is connectionless.
These days you can do both.
There are also other libraries than the standard one, and early days you basically wanted these for their features (such as DHCP, DNS, UDP, OSC, Bonjour) and/or other boards. (see e.g. [3], [4], [5])
(particularly DHCP and DNS are handy as it means you need no hardcoding beyond a unique MAC)
See also:
- http://www.arduino.cc/en/Guide/ArduinoEthernetShield
- http://www.arduino.cc/en/Reference/Ethernet (Arduino library for the Wiznet shield)
Other libraries:
- http://bitbucket.org/bjoern/arduino_osc/src/tip/libraries/Ethernet/
- http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1239258729/37#37
Similar devices:
Some code
- include <SPI.h>
- include <Ethernet.h>
- include <EthernetUdp.h>
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
EthernetUDP udp_endpoint;
EthernetServer tcp_server = EthernetServer(7);
- define MY_PACKET_BUFFER_SIZE 100
char packet_buffer[MY_PACKET_BUFFER_SIZE];
void setup() {
Serial.begin(115200);
Serial.println("setup()");
/******** DHCP **********/
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet");
// no point in carrying on, so do nothing forevermore:
while (true) {
Serial.println("DHCP failure; will reset via watchdog");
delay(1);
}
}
// print your local IP address:
Serial.print("My IP address: "); Serial.println(Ethernet.localIP());
Serial.print("Subnet mask: "); Serial.println(Ethernet.subnetMask());
Serial.print("Gateway: "); Serial.println(Ethernet.gatewayIP());
Serial.print("DNS server: "); Serial.println(Ethernet.dnsServerIP());
udp_endpoint.begin(7);
}
void loop() {
switch (Ethernet.maintain()) {
case 2:
Serial.println("Renewed success");
Serial.print("My IP address: ");
Serial.println(Ethernet.localIP());
break;
case 4:
Serial.println("Rebind success");
Serial.print("My IP address: ");
Serial.println(Ethernet.localIP());
break;
case 1:
Serial.println("Error: renewed fail");
while (true) { delay(1); } // loop to trigger watchdog
break;
case 3:
Serial.println("Error: rebind fail");
while (true) { delay(1); } // loop to trigger watchdog
break;
default:
break;
}
/******** TCP ***********/
EthernetClient tcp_client = tcp_server.available();
if (tcp_client) {
Serial.print("[TCP] Received packet of size ");
Serial.println( tcp_client.available() );
Serial.print("[TCP] From ");
IPAddress remote = tcp_client.remoteIP();
for (int i = 0; i < 4; i++) { Serial.print(remote[i], DEC); if (i < 3) { Serial.print("."); } }
Serial.print(", port ");
Serial.println(tcp_client.remotePort());
int s=min(tcp_client.available(), MY_PACKET_BUFFER_SIZE);
tcp_client.read(packet_buffer, s);
Serial.print("[TCP] Contents:");
for (int j=0;j<s;j++) {
Serial.print( (unsigned char)packet_buffer[j], HEX);
Serial.print(" ");
}
Serial.println("");
Serial.println("");
tcp_client.write( packet_buffer );
tcp_client.stop();
}
/******** UDP ***********/
int packetSize = udp_endpoint.parsePacket(); // sets _remainging
if (packetSize) {
Serial.print("[UDP] Received packet of size ");
Serial.println(packetSize);
Serial.print("[UDP] From ");
IPAddress remote = udp_endpoint.remoteIP();
for (int i = 0; i < 4; i++) {
Serial.print(remote[i], DEC);
if (i < 3) {
Serial.print(".");
}
}
Serial.print(", port ");
Serial.println(udp_endpoint.remotePort());
// read the packet into packetBuffer
int s=min(packetSize, MY_PACKET_BUFFER_SIZE);
udp_endpoint.read(packet_buffer, s);
Serial.print("[UDP] Contents:");
for (int j=0;j<s;j++) {
Serial.print( (unsigned char)packet_buffer[j], HEX);
Serial.print(" ");
}
Serial.println("");
Serial.println("");
}
}