How to use an Arduino Ethernet Shield with the Nordic Semiconductor nRF51-DK

Aaron ArdiriBlogs, Tutorials

Tweet about this on TwitterShare on FacebookShare on LinkedInShare on Google+

nrf51-dk-ethernet The Nordic Semiconductor nRF51 Developer Kit, an mbed.org enabled micro-controller, is the first of its kind from Nordic Semiconductor that is compatible with the Arduino UNO rev3 hardware standard – however it lacks any form of on-board Ethernet connectivity.

It was obvious for us and our hands-on tendencies to figure out exactly how to utilise the Arduino Ethernet Shield and give the nRF51-DK Ethernet support – in this post we’ll show you exactly how we went about doing so!

Hardware checklist

In order to walk through this tutorial on your own; you’ll need at least the following equipment:

It should not be necessary to go into detail what each component is for; the most important thing is you will need to have the nRF51-DK connected to your computer’s USB port for debugging and make sure both are connected to the same network so they can communicate.

In this tutorial; we will be using a Macbook Pro running Mac OSX 10.9.5 – however, it should be easily adaptable to work with a Windows or Linux environment as well. We are under the assumption that you have previously seen the earlier post where we introduced mbed.org and the nRF51-DK.

Creating a foundation for our mbed OS application

In order to create our mbed OS application – we need a simple as possible starting point.

The simplest starting point that does not bring in too many dependencies is to find a hello world type application – simply press the “Import” button and search for anything of this nature, you should be presented with a list similar to what is shown below. A number of results will be suitable – we only need to have the structure and we’ll be replacing the main.cpp file with our own shortly anyhow.

nrf41-dk-ethernet-import-program

We used the most popular example – clicking on the big “Import” button we are presented with:

nrf41-dk-ethernet-import-program-helloworld

This is where we can specify the name of our application (mbed-nordic_ethernet) and import it as a program. It is very important to select the checkbox where it asks to update the libraries to the latest revision – failure to do so could result in compiler errors for no reason.

Integrating an library to support the Ethernet chipset

A number of micro-controller providers have established integrated Ethernet development boards – such as NXP, freescale and Renesas which the mbed.org team has worked very hard on to provide a generic Ethernet and Socket interfaces that support these boards within the mbed driver layers.

While investigating the possibility for using such libraries with the nRF51-DK, I came across a question on the mbed.org forums where another developer had asked if the library would support other chipsets; unfortunately the answer provided was:

No, EthernetInterface is only for the boards listed there, who have an integrated Ethernet peripheral. The F411 does not have this (at least I don’t think it has one, for sure it is not supported). You will need an external ethernet board with its own library.Erik Olieman @ developer.mbed.org

I also actively participated in the discussion – posting a few suggestions for supporting external boards within the same common Ethernet interface. It would make sense to provide a uniform Ethernet interface regardless if the chipsets are internal or external.

It was time to do some legwork to see what could be achieved here – not for the faint hearted!

The first step was to take a look at the Arduino Ethernet Shield hardware specification – as surely there wasn’t going to be a library posted by Arduino for mbed OS on the website. With a bit of digging, via using a magnifying glass to look at the chip manually, searching the internet and finally resorting to the Arduino ethernet driver source code – it was clear the chip being used as a WIZnet 5X00 variant (5100 or 5200 – depending on the revision of the board that you are using).

After some research; I found a number of libraries that were supposed to support the 5200 variant; however, my board had a 5100 chip and things just didn’t work as expected until finally I came across a WIZnet library that supported all the 5100, 5200 and 5500 chipsets in a single library. It was like finding a needle in a haystack; very welcome as I was on the verge of giving up completely.

To import this library; use the “Import” button again and search for the “wiznet” library.

nrf41-dk-ethernet-import-library

It should be prominently displayed – clicking on the big “Import” button we are presented with:

nrf41-dk-ethernet-import-library-wiznet

This is where we can select which program to import it into (mbed-nordic_ethernet) and import it as a library. It is very important to select the checkbox where it asks to update the sub-libraries to the latest revision again – failure to do so could result in compiler errors for no reason.

Unfortunately; If you look closely at the resulting project – you will see that the WIZnet library also includes a main.cpp and mbed asset. If you try to compile the project in this state – the compiler will complain that there are two main() functions defined. The best thing to do is simply delete the main.cpp that exists within the WIZnet_Library folder – as shown below.

nrf41-dk-ethernet-import-library-post_actions

If you are a purist like myself; you could also delete the mbed resource in the library folder – as you can see we obtained that when we imported the hello world program. They may have structured it this way so the library could be imported as a program with a example to start working from.

In any event; we’ve taken the example provided – fixed a few bugs and made it clearer for you to understand so it will just be a matter of replacing the contents of the main.cpp file within the root of the project to complete this tutorial and keep it as simple as possible.

Modifying the WIZnet example for the nRF51-DK

This is where the real fun starts and you get your hands really dirty – but bear with us!

Since we deleted the main.cpp file earlier – we will need to use a reference copy of the file which is readily available on the mbed.org code repo – inside you will see a little bit of code where you set the platform you wish to target, if you have one of these boards you are good to go!

/** 
 * Setting the platform to test
 */
  #define LPC
//#define ST_NUCLEO
//#define FRDM_KL25Z
//#define Seeeduino_Arch

Every micro-controller may end up with different pin mappings and we need to let the library know which ones to use. Unfortunately; the Nordic Semiconductor nRF51-DK is not in this list so we are going to have to find the correct pin assignments to make the library work with the hardware.

The Arduino Ethernet Shield requires pins for its SPI interface and since the shield also has a dual purpose, there is a selector pin to switch modes between the Ethernet and SD card functionalities provided on the shield. In micro-controller speak; we need to find mappings for MOSI, MISO, SCLK, CS (cable select) and RESET so the library knows which pins to send digital signals to.

Arduino nRF51-DK
MOSI 11 / ICSP-4 P0_25
MISO 12 / ICSP-1 P0_28
SCLK 13 / ICSP-3 P0_29
CS 10 P0_24
RESET ICSP-5 P0_0

The Arduino Ethernet Shield also has an ICSP header; however in testing it was evident these were not interfacable. We do not technically require the RESET pin, but since the library tries to interact with it we just map it to P0_0. The resulting configuration of the spi and eth objects are:

SPI spi(P0_25, P0_28, P0_29);              // MOSI, MISO, SCLK
WIZnetInterface eth(&spi, P0_24, P0_0);    // spi, CS, RESET

A modified version of the sample application provided in the library (with a few fixes) and cleaned up for simplicity is below – simply cut and paste this into the main.cpp file within the root of the project. If you have not yet removed the main.cpp file in the WizNet_Library directory – you should do this now to prevent conflicts when compiling.

/*
 *  Echo program for nRF51-DK with Arduino Ethernet shield using mbed.org
 */

#include "mbed.h"
#include "WIZnetInterface.h"

#define INFO(x, ...)    printf("[main.cpp:INFO] " x "",     ##__VA_ARGS__);
#define INFO_NL(x, ...) printf("[main.cpp:INFO] " x "\r\n", ##__VA_ARGS__);

#define USE_DHCP
#define ECHO_PORT 5000

#ifndef USE_DHCP
const char *IP_Addr    = "192.168.1.2";
const char *IP_Subnet  = "255.255.255.0";
const char *IP_Gateway = "192.168.1.1";    // put your own values here
#endif

SPI spi(P0_25, P0_28, P0_29);              // MOSI, MISO, SCLK
WIZnetInterface eth(&spi, P0_24, P0_0);    // spi, CS, RESET
Serial pc(USBTX,USBRX);

int main()
{
    uint8_t mac[6];
    
    // set these to match the mac address on the Arduino Ethernet Shield
    mac[0] = 0x90; mac[1] = 0xa2; mac[2] = 0xda; 
    mac[3] = 0x0f; mac[4] = 0x0e; mac[5] = 0x63;  // 90:a2:da:0f:0e:63
    
    INFO_NL("Start");
#ifdef USE_DHCP
    int ret = eth.init(mac);
#else
    int ret = eth.init(mac, IP_Addr, IP_Subnet, IP_Gateway); 
#endif

    if (!ret) { INFO_NL("Initialized, MAC: %s", eth.getMACAddress()); } 
    else      { INFO_NL("Error eth.init() - ret = %d", ret); return -1; }

    ret = eth.connect();
    if (!ret) { INFO_NL("IP: %s, MASK: %s, GW: %s",
                        eth.getIPAddress(), 
                        eth.getNetworkMask(),
                        eth.getGateway()); } 
    else      { INFO_NL("Error eth.connect() - ret = %d", ret); return -1; }

    TCPSocketServer server;
    server.bind(ECHO_PORT);
    server.listen();

    while (true) 
    {
        INFO_NL("Wait for new connection...");
        
        TCPSocketConnection client;
        server.accept(client);
        
        INFO_NL("Connection from: %s", client.get_address());
        char buffer[256];
        while (true) 
        {
            int n = client.receive(buffer, sizeof(buffer) - 1);
            if (n <= 2) break;
            buffer[n] = 0;            
            INFO(" %s", buffer);

            client.send_all(buffer, n);
        }
        INFO_NL("Connection closed");

        client.close();
    }
}

The WIZnet library supports three different variants of the W5X00 chipset – by default the assuming the use of the W5500 chipset, which is configured within the header file stored in the libary under WIZnet_Library/WIZNetInterface/WIZnet/wiznet.h – as shown below.

  #define USE_W5500
//#define USE_W5200
//#define USE_W5100

It is vital to change the #define used to match the chipset that is provided with your Arduino Ethernet Shield. If you are running into issues – try the various variants; we had to use W5100.

Compiling and flashing the program

Within the compiler view on the mbed.org developer site select the target platform – in this case it will be the platform named “Nordic nRF51-DK” and then press the “Compile” button within the web based IDE. If everything goes ok; it should offer you the following file for download:

mbed-nordic_ethernet_NRF51_DK.hex

Simply connect the nRF51-DK to the computer and copy the hex file to the external storage medium that is presented. We covered the deployment process in our previous post with the nRF51-DK. Now that the application has been flashed to the nRF51-DK it is time to see it in action!

Verification and seeing it in action!

Ensure that the nRF51-DK is freshly connected to the USB port of your computer; the easiest way to make sure is to disconnected it and reconnected it so that we do not run into any conflicts with the device being busy. After a few seconds, our application should be executing.

The easiest way to find out if the device has established a network connection is to look at the debugging logs our program has written to the console – to do this, we must establish a connection to the USB port using a serial program; such as screen within a Terminal session.

$ screen /dev/tty.usbmodem1411

[main.cpp:INFO] Initialized, MAC: 90:A2:DA:0F:0E:63
[main.cpp:INFO] IP: 192.168.1.136, MASK: 255.255.255.0, GW: 192.168.1.1
[main.cpp:INFO] Wait for new connection...

Your nRF51-DK may have a different name to /dev/tty.usbmodem1411 however it will be very similar to this; if you are on Mac OSX or Linux they have this type of name, on Windows of course this would be a COMxx port and you could also use a program like HyperTerminal (instead of screen) to establish communication with the board.

The debugging output shows the board has the IP address of 192.168.1.136. This is all the information we need to know so we can attempt to establish a telnet connection on port 5000 to the device – which of course needs to be done in a separate Terminal session.

$ telnet 192.168.1.136 5000
Trying 192.168.1.136...
Connected to 192.168.1.136.
Escape character is '^]'.

At this point – we can see the debugging console should have also accepted a connection – simply type some text and whatever you enter will be echoed back to your session and be simultaneously presented in the debugging console. To close the connection; simply press enter twice.

A screen capture of the debugging console and the communication console is shown below:

nrf51-dk-ethernet-demo

You should see something similar – if so you have verified adding Ethernet support to the nRF51-DK.

Why not take a moment to download Evothings Studio and see if you can write a mobile application that communicates with the nRF51-DK over TCP/IP; a great example called Arduino LED On/Off TCP would not be difficult to modify and get working with the nRF51-DK.

We would love to continue our series working with the Nordic Semiconductor nRF51-DK; if you would like to see anything specific or have any questions about how to work with these devices and create some cool and interesting products – why not head over to our forums and let us know!