Update (December 8, 2010): The below information of the required Arduino hardware is obsolete and left here for informational purposes. Look at this newer post for updated information on the new hardware.
Arduino TinyWebServer is a small and extensible HTTP server
implementation designed to run in a limited amount of space on an
Arduino Duemilanove. It uses
the Ethernet Shield for network connectivity (from Sparkfun or from Adafruit), and
the Adafruit
Data Logging shield for storage purposes.
Web pages, images and other content can be copied manually on the
SD card or uploaded through the HTTP server. The latter allows you to
push new versions of the web server's content without the need to
remove the card, which can be a pain in embedded applications.
In the first part I present some changes that have to be made to the hardware used and its accompanying software. Part two presents a small open source software library that implements the Arduino TinyWebServer.
Hardware modifications: Data Logging shield
The hardware shields need few modifications in order to work
together. The cards were designed to work independently and use the
default pins allocated on the hardware SPI bus (the CS, MOSI, MISO and SCK
lines on the 10, 11, 12, 13 pins on an Arduino Duemilanove). When
stacking the boards together they'd end up in a bus conflict and they won't work.
The conflict is solved by having the two boards use different CS
pins. They can still share the MOSI, MISO and SCK lines, and if it wasn't for a buggy chip on the Ethernet shield, we'd have ended up using only 5 total digital I/O pins for the whole setup. See below for more info.
To make things easy, I chose to use a different CS pin for the Adafruit Data
Logging shield: I use pin 9 as the CS pin. For this to work, first make sure you cut out the original trace that goes to pin 10, as in the picture below.
The Data Logging shield board comes unassembled. After you solder all the components on it, run a wire from the CS pin to pin 9, as shown in the picture below.
Hardware modifications: Ethernet shield
The Ethernet shield uses a Wiznet W5100 chip, which has a buggy hardware SPI implementation. In a post on Adafruit's forum, jaredforshey pointed me to this Arduino playground page which points to an easy way to fix this.
The proposed solution disables the chip' SPI part when not in use. This is done by connecting pin 8 to the lower PAD on the board, as shown below. At the same time, make sure you cut the trace leading from pin 8. This bug ends up costing us another pin, for a total of 6 I/O pins for the whole setup.
Software modifications: Fat16 library
To read and write files on an SD card, we need to be able to access a file system on the SD card. There are two main file systems used on SD cards: FAT16 and FAT32. The main differences between them are the maximum card sizes supported and more importantly, file naming conventions. FAT16 allows only the old 8.3 DOS file format and cards up to 2GB.
Arduino supports both file systems on SD cards using either of these libraries: Fat16 or SdFat. For all its limitations, FAT16' library is smaller that FAT32, so I decided to go with it.
Our Data Logging shield uses pin 9 as the CS pin. The FAT16 library assumes the CS pin used in pin 10, so we need to modify that in the code. For Arduino Duemilanove, the definition of SPI_SS_PIN in SdCard.h needs to change from 10 to 9.
Software modifications: Arduino's Ethernet library
The Ethernet library shipped with the Arduino 018 package has a bug. In the Client class in Client.h , the read() method does not differentiate between an 0xFF byte and the Ethernet hardware not having data available. This is not usually a problem if all you serve through the Web server are text files, including HTML. However for any binary file, including images, zip files etc. this however is a problem.
To fix this problem, I've added two more methods to the Client class:
int read(uint8_t* ch);
int read(uint8_t *buf, size_t size);
The first reads a character and puts its value at the address pointed to by ch . The method returns 1 if it succeeded reading a character, 0 otherwise (as when there is no data available). The second method fills in the value of buf with as many characters as it can, up to size . It returns the number of characters it was able to read, or 0 if none were read. Here is how they're implemented:
int16_t Client::read(uint8_t *ch) {
if (!connected() || !available()) {
return 0;
}
return recv(_sock, ch, 1);
}
int16_t Client::read(uint8_t *buf, uint16_t size) {
uint16_t i;
for (i = 0; i < size; i++) {
if (!read(buf + i)) {
break;
}
}
return i;
}
The second change to the Ethernet library is in utility/spi.h , to fix the hardware bug with the Wiznet chip. This change is described on the Arduino playground page.
|