Department of InformatiX
Microsoft .NET Micro Framework Tools & Resources

First steps with Visual Studio and GPIO

This part is intended for absolute beginners in .NET Micro Framework. We are going to write a really simple application, which will light the LED while a button is pressed. We will use the Tahoe board as a hardware platform, but the steps are the same for other hardware, as well as for emulator.

Required software installation

  1. Visual Studio 2008 SP1 is needed, or the Visual C# 2008 Express Edition. If you don't have one, you can download 90-day trial of Professional edition from here for free (for purposes of .NET Micro Framework, selecting C# for installation is just fine), the Express edition is available here. Students can download development tools at the DreamSpark server.
    • Visual Studio 2008 supports targeting the .NET Micro Framework 4.0 and 3.0. If you need to develop for lower versions, you would need Visual Studio 2005.
    • Microsoft yet supports C# only. If you are advanced user, you can deploy assembly created in any .NET language, but without debugging capabilities.
  2. Next you need the .NET Micro Framework itself. You get it in the form of SDK (Software Development Kit). You can download the last (fourth) version here for free.
    • The other versions are listed in links.
    • The SDK is needed even if you want to use emulator only. In that case you can choose whichever version you want.
    • The original Tahoe board is shipping with framework version 2.5 preinstalled. You can upgrade the firmware to 3.0 version with a very easy tool from vendor.
  3. Download and install the SDK for your hardware. I use Tahoe in this example, which SDK can be downloaded from here.
    • Even if you don't have your favorite hardware yet, you can usually install and use the SDK without it.
    • Some vendors put additional emulators into the SDK, which are closer to the real devices, and more detailed documentation.
    • If you are looking for the built-in Microsoft emulator only, you can skip this step.
  4. If you do have the hardware, connect it to the computer using supplied USB cable. If Windows fail to install it, you can find (in the case of Tahoe) the drivers in the folder you have installed SDK in, in subfolder Drivers.
    • If you are powering the device from the USB cable only, be careful to connect it to the port which supplies enough power according to the USB standard. Typically avoid hubs and some notebooks. If you find that the device is having troubles starting up (like empty display), try to connect it directly to the PC.

Creating a new project

  1. Create new project. In menu File choose New | Project.... The SDK installation extended the Visual Studio project templates:
    New Project dialog
    Find a Visual C# node left in the tree, expand it and click on the Micro Framework. We will be happy with Console Application for this example, so choose and create this one.
  2. We have to set up where we want our application to be deployed. Click on the name of the project inSolution Explorer using the right button
    Properties menu item
    and choose Properties. A new document with tabs will open. Click the .NET Micro Framework one and choose USB in the Transport list:
    project properties
    If everything went right, you will see your device's name in the Device list, in this case Meridian_ followed by its unique identifier.
    Device: Meridian_xxxxxxxx
    You can close the project properties now.
    • If you do not have the hardware, choose Emulator as a Transport type, and TahoeEmulator in Devices list.
    • You can set the device's USB name using the MFDeploy utility as you wish, located in the folder you installed .NET Micro Framework SDK into, Tools subfolder.
  3. To work with input and outputs, we will need to add references to some assemblies. Click on the References folder in Solution Explorerusing the right button
    Add Reference... in menu
    and choose Add Reference.... We definitely need Microsoft.SPOT.Hardware, and just for comfort select DeviceSolutions.SPOT.Hardware.Meridian and DeviceSolutions.SPOT.Hardware.Tahoe as well (we will use only constants for pins from these two).
    Add Reference dialog
    • You can select more assemblies at once by holding the Ctrl key during selection.

Writing the application

  1. Open the code by double-clicking the Program.cs in Solution Explorer. Declare two variables, LED, which is for the diode, and SW7 for the middle button on Tahoe board. The Microsoft.SPOT.Hardware.OutputPort class is for working with the output ports, the Microsoft.SPOT.Hardware.InterruptPort for input ones, interrupt capable. The variables are going to be static so that we can access them from static methods. So right before the Main method type static OutputPort:
    variable declaration
    From the color and list you can see that OutputPort is not known by Visual Studio. The reason is that it is hidden in the Microsoft.SPOT.Hardware namespace, which we are not using yet. However, a little rectangle appeared just under the letter t and when you click it,
    Smart Tag menu
    you will be offered a couple of options how to fix that. Let's choose using Microsoft.SPOT.Hardware; so we won't have to repeat it with every class in this namespace and to keep the code clean.
    So the final declaration looks like this:
    public class Program { static OutputPort LED; static InterruptPort SW7; public static void Main() { ...
    • A keyboard shortcurt for the Smart Tag options (expanding the rectangle) is Alt+Shift+F10.
  2. Initialize the variables in the Main method, which is called upon start of the application in the processor.
    The OutputPort constructor takes two arguments - a number of pin and initial state. Choose GPIO1 from DeviceSolutions.SPOT.Hardware.Meridian class for example, and false.
    The InterruptPort constructor is a bit more hungry:
    • The pin number is DeviceSolutions.SPOT.Hardware.Tahoe.SW7.
    • The second one gives you the option to turn on the glitch filter, which we do not need now; choose false.
    • You need to tell what kind of pull resistors do you want the processor to use on that pin. You can usually find supported values in the documentation, or you can just try it (an exception is thrown if you miss). Tahoe uses pull-up resistors only, which is represented by Microsoft.SPOT.Hardware.Port.ResistorMode.PullUp value.
    • And the last one is when you want to fire the interrupt. We are interrested in both rising and falling edges (in both cases we want to update the LED) - Microsoft.SPOT.Hardware.Port.InterruptMode.InterruptEdgeBoth.
    If you added required namespaces, the initialization should look like this:

    LED = new OutputPort(Meridian.Pins.GPIO1, false); SW7 = new InterruptPort(Tahoe.Pins.SW7, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
    • Not all hardware supports monitoring both edges at once or a glitch filter, read the documentation carefully.
  3. Now we create an interrupt handling routing. We will use an OnInterrupt event of InterruptPort class for that. So type SW7.OnInterrupt += just after the initialization
    attaching an event handler
    and press the Tab twice, which causes the Visual Studio to generate both event subscription code and the handling routine skeleton:
    ... SW7.OnInterrupt += new NativeEventHandler(SW7_OnInterrupt); } static void SW7_OnInterrupt(uint data1, uint data2, TimeSpan time) { } }
    • As suggested by the += operator, one interrupt can call multiple methods. Different interrupts can call a common method as well.
  4. The NativeEventHandler is a new delegate for handling various native events. For this reason, there were choosen quite generic names and types for its parameters. In the case of InterruptPort events, we have this parameters in the SW7_OnInterrupt method:
    • data1 - a number of pin which caused the interrupt (can be casted to Cpu.Pin, Tahoe.Pins or any other enum)
    • data2 - actual value on that pin (in our non-zero value means the edge was rising, zero means falling)
    • time - a CPU time at which the interrupt happened
    We will perform two tasks upon the interrupt: write out when it happend and change the diode state in an appropriate way. You can output text using Debug.Print during debugging and change the output port value using OutputPort.Write:
    static void SW7_OnInterrupt(uint data1, uint data2, TimeSpan time) { Debug.Print(time + ": Button " + (data2 == 0 ? "pressed" : "released")); LED.Write(state == 0); }
    • When using pull-up resistors, buttons connect the processor pins to the ground. There is a voltage on the pin when a button is released. This is why 1 means released and 0 pressed, and we also need to write an inverted value to the diode.
    • There is no Console.WriteLine method in .NET Micro Framework, neither any else capable of formating strings like "{0}: Button {1}".
    • Debug.Print is being completely omitted during compilation in Release configuration.
    • Good practice is to rename the data1 and data2 parameters to something more meaningfull, like port and state.
  5. The last thing we have to do is to keep the processor alive when no button is being pressed. Our program would terminate almost immediately now. We will fix that be putting the thread into a sleep using the System.Threading.Thread.CurrentThread.Suspend() statement, which allows the processor to switch to low-power mode during inactivity.
    The final code follows:

    using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using DeviceSolutions.SPOT.Hardware; namespace MFConsoleApplication1 { public class Program { static OutputPort LED; static InterruptPort SW7; public static void Main() { LED = new OutputPort(Meridian.Pins.GPIO1, false); SW7 = new InterruptPort(Tahoe.Pins.SW7, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth); SW7.OnInterrupt += new GPIOInterruptEventHandler(SW7_OnInterrupt); Thread.CurrentThread.Suspend(); } static void SW7_OnInterrupt(uint data1, uint data2, TimeSpan time) { Debug.Print(time + ": Button " + (data2 == 0 ? "pressed" : "released")); LED.Write(data2 == 0); } } }

Running the application and debugging

  1. Running the application is easy. Just click Debug | Start Debugging in the menu. You can press the middle button on Tahoe (or in the Tahoe emulator) and watch the Output window. debugging
    If you put a cursor on the LED.Write(state == 0); line and click Debug | Toggle Breakpoint, you will create a breakpoint, which means that the application execuction pauses as soon as it reaches the marked statement (try to press the button after creating the breakpoint).
    • A keyboard shortcut for debugging start is F5, for toggling breakpoints use F9.
    • If you can't see the Output window, you can show it at runtime using View | Output menu.
  2. So what now? For example:
    • If you hover over a variable name, you will see its value in a kind of tooltip window. You can even change the value by clicking on it.
    • The Autos window (menu Debug | Windows | Autos) presents you all variables used around the statement you are currently breaked on, including their types and values.
    • You can write statements to Immediate (menu Debug | Windows | Immediate) which will get immediately executed,
      okno Immediate
      eg. manually switch on or off the diode, just try it!
    • You can also see a list of all threads currently running on the device, in the Threads window (menu Debug | Windows | Threads).
      okno Threads
      To easily find out what a thread does, double-click on it.
    • Unfortunately you cannot modify the code at runtime.
  3. To stop the debugging use Debug | Stop Debugging (or Shift+F5).

Connecting the diode

You cannot connect common LED directly to the processor, as it is capable of delivering only specified amount of current. To avoid damaging the processor, we have to limit the current using a resistor. You have two options: either compute the required resistor value and connect it with diode in series, or get a diode with a built-in resistor.

How to find out the required resistore value? You need to know three things:

The requested resistor value is then computed as (Upin – Uf) / Isrc, in our case (3.3 V – 2 V) / 0.004 A = 325 Ω.

The other option is to not search nor compute anything, put e.g. 5 kΩ there just for sure. The only thing which can happen is that the LED won't shine very much.


The last problem is how to wire the diode. For example, Tahoe has all pins accessible through 0.1" male connectors:
connectors on Tahoe

LED with socketsYou can create some wires yourself of course, or solder the female parts directly to the diode. But if you have a free IDE or floppy cable, you can connect it directly to the Tahoe! The pin-out is kept the same, but this time on a connector into which you can easily insert wires. In this case however, when all we need is to connect two wires, some cables from inside of PC could be enough, like those from motherboards (to buttons, fans, or LEDs) or like betwen sound card and CD drive (be it analogue or digital one).

The GPIO1 pin which we choosed in the application is (not exactly by chance) placed just directly opposite the ground (0V). You can also test the diode before by placing it between 0V and 3.3V, which are also just on the next pin to the GPIO1. Cathode is called the part of diode which belongs to the ground. You can recognize it either by shorter wire, or by flat lighting part on that side. In either case, the diode will just not work if connected badly.

LED with sockets directly on Tahoe.
Notice the flat side connected to 0V.

These LEDs have built-in resistor,
don't connect them directly without it!

LED connected using the IDE cable.

Isn't that easy? ;-)

Sign in using Live ID to be able to post comments.