projects

Ethernet hwaddr and EEPROM storage with Arduino

Posted by mitch on October 31, 2012
hardware, projects, software

There are lots of examples of how to use the Ethernet Wiznet chips with Arduino, whether as Ethernet shields or as Ethernet Arduinos on a single board. Unfortunately, most of these examples hard-code the hardware (MAC) address, which can make things painful if you’re building more than one device and running them on the same network.

The code snippet below is a more convenient approach. You can setup a prefix (DEADBEEF in the example below) for the hardware address and the last two bytes are set randomly on first boot. The hardware address is stored in EEPROM (7 bytes are needed, 1 for a flag indicating that the next 6 bytes are properly populated).

The bytes->String conversion below is a bit ugly but I didn’t think I wanted the overhead of sprint in this. It is probably not worth the trade off. (0x30 is ‘0’ and 0x39 is ‘9’. Adding 0x07 skips over some ASCII characters to ‘A’.)

Some serious caveats: There’s only two bytes of randomness here. You might want more. Ideally you would have a manufacturing process, but if you’re just building six devices, who cares? Clearly you would never use this approach in a production environment, but it’s easier than changing the firmware for every device in a hobby environment. You could also use a separate program to write the EEPROM hardware address and keep this “manufacturing junk” out of your main firmware. These issues aside, my main requirement is convenience: I want to be able to burn a single image onto a new board and be up and running immediately without having to remember other steps. Convenience influences repeatability.

#include <Ethernet.h>
#include <EEPROM.h>

// This is a template address; the last two bytes will be randomly
// generated on the first boot and filled in.  On later boots, the
// bytes are pulled from EEPROM.
byte NETWORK_HW_ADDRESS[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00};
String NETWORK_HW_ADDRESS_STRING = "ERROR_NOT_FILLED_IN";

// These are commented out so that this code will not compile
// without the reader modifying these lines.  If you are using
// EEPROM code in your program already, you need to put the
// network address somewhere that doesn't collide with existing use.
//#define EEPROM_INIT_FLAG_ADDR 0
//#define EEPROM_HWADDR_START_ADDR 1

// Call this from your setup routine (see below)
void
initEthernetHardwareAddress() {
    int eeprom_flag = EEPROM.read(EEPROM_INIT_FLAG_ADDR);  
    int i;
    Serial.print("EEPROM flag is " + String(eeprom_flag));
    
    if (eeprom_flag != 0xCC) {
        NETWORK_HW_ADDRESS[4] = random(255);
        NETWORK_HW_ADDRESS[5] = random(255);  
        
        // write it out.
        Serial.println("Writing generated hwaddr to EEPROM...");
        for (i = 0; i < 6; i++) {
            EEPROM.write(EEPROM_HWADDR_START_ADDR + i + 1,
                         NETWORK_HW_ADDRESS[i]);
        }

        EEPROM.write(EEPROM_INIT_FLAG_ADDR, 0xCC);
    } else {
        Serial.print("Reading network hwaddr from EEPROM...");
        for (i = 0; i < 6; i++) {
            NETWORK_HW_ADDRESS[i] =
                EEPROM.read(EEPROM_HWADDR_START_ADDR + i + 1);
        }        
    }
    
    char hw_string[13];
    hw_string[12] = '\0';
    for (i = 0; i < 6; i++) {
        int j = i * 2;
        
        int the_byte    = NETWORK_HW_ADDRESS[i];
        int first_part  = (the_byte & 0xf0) >> 4;
        int second_part = (the_byte & 0x0f);
        
        first_part  += 0x30;
        second_part += 0x30;
        
        if (first_part > 0x39) {
            first_part += 0x07;
        }
        
        if (second_part > 0x39) {
            second_part += 0x07;
        }
        
        hw_string[j] = first_part;
        hw_string[j + 1] = second_part;
        
    }

    NETWORK_HW_ADDRESS_STRING = String(hw_string);

    Serial.println("NETWORK_ADDR = " + NETWORK_HW_ADDRESS_STRING);
}

void
setup() {
    // first call the usual Serial.begin and so forth...

    // setup the Ethernet hwaddr before you start using networking
    initEthernetHardwareAddress();

    int dhcp_worked = Ethernet.begin(NETWORK_HW_ADDRESS);

    // ...
}

Quick Dual Timezone Clock Design

Posted by mitch on January 17, 2012
projects

I have long wanted a dual timezone clock for my desk but I never found one that I liked. Most of the multi-timezone clocks on the market are for 3 or 4 timezones and are gaudy analog displays or ultra utilitarian digital displays. Why not build one using an Arduino board as the base? This would enable a number of integration opportunities with Internet services.

I’m planning on having two screens on the clock, each of them 128×64 pixel monochrome displays. Driving one of these screens requires a significant number of I/O lines, so this design will benefit from using an Arduino Mega board, though I haven’t yet confirmed that the Mega has enough lines without some type of mux.

The model above shows an approximate mockup that I threw together while flying earlier today. The clock is about a 2×2.5×7″ rectangular prism with a triangular subtraction so that the screens can be tilted. I suspect the length can be shrunk to 6″ or less; there’s a lot of empty space in the above model. The Ethernet RJ45 and power jacks are moved from the Arduino boards to a separate board so that the main boards can be mounted vertically but the wires are still on the back of the clock.

I have a few software features in mind:

  1. NTP sync on power-on and thereafter syncing once per day. This has the obvious advantage of never having to set the clock and also enables using a cheaper real-time clock chip with a few seconds of drift per day.
  2. The above requires Ethernet. The Arduino Ethernet shield gets the job done.
  3. A simple web interface to configure the timezones and perhaps zip codes so that some weather information can be displayed for each location.
  4. A button on the back of the clock to show the DHCP-collected IP address.
  5. Perhaps a bit of integration with a calendar feed to show upcoming events on the calendar. This will likely require some kind of middleware that the clock communicates with. I am not sure I will take it this far.

PoE would be a cool addition but I’m not sure I want to mess with it for this project.

I’ll post again when I have more than vaporware. I ordered the LCD screens this weekend.

Tags: