The .NET Micro Framework: A First Look

If you are like most developers, you've heard of Microsoft's .NET Framework. If you have heard of the .NET Framework, you might also have heard of the .NET Compact Framework that was created for mobile devices. What you might not have heard about is the .NET Micro Framework.

The .NET Micro Framework is not the same thing as the .NET Compact Framework. Rather, it is yet another version of the .NET Framework, but this time targeted specifically to embedded systems. Of course, you might have heard of the Microsoft Embedded ToolKit. The .NET Micro Framework is also not the same thing as the Embedded Toolkits that Microsoft has available.

The .NET Micro Framework is a scaled-down version of the .NET Framework targeting embedded systems development using Managed code, and more specifically, C#. The .NET Micro Framework is a scaled-down version of the .NET Framework that is more specific to embedded devices.

In Figure 1, you can see the software architecture. As you can see, the .NET Micro Framework includes a runtime, libraries, and more. Also included in the architecture is an abstraction layer for the hardware (HAL). Whereas embedded applications are generally written to specifically target hardware, that is not the case with the .NET Micro Framework. As an embedded developer, you would use the standard routines in the library. The hardware vendor you use would then provides the underlying abstraction layers of the HAL along with an abstraction layer for the platform (PAL).

Figure 1: The .NET Micro Framework Architecture

When you get a piece of embedded hardware, the hardware manufacturer should supply you with a copy of the .NET Micro Framework. The version they give you will have their HAL and PAL included. The result is that you can write standard, Managed C# code using standard libraries. If you change hardware, you should only need to swap to the new hardware's copy of the .NET Micro Framework, which will replace the HAL and PAL. Your program should require no changes as long as the hardware is similar.

The .NET Framework's object model is smaller than the .NET Compact Framework and obviously smaller than the full .NET Framework. The framework can fit in as little as 256 Kb of RAM along with as little as 512 Kb of flash memory. In that tiny bit of space, you get a number of the classes that .NET Developers already know. This include threading, text, reflection, streaming, debugging, ArrayList, math, and much more. Figure 2 shows an abridged version of the object model.

Figure 2: Programming libraries in the .NET Micro Framework (abridged)

It is worth pointing out that the .NET Micro Framework is not a direct subset of the the .NET Frameworks. In some cases, classes have been moved to other libraries. This was done for the sake of easing navigation and providing a tight focus to keep things small.

The .NET Micro Framework: A First Look

Developing for the .NET Micro Framework

An SDK that you can install on top of Visual Studio has been provided. You can use Visual Studio 2005 or later to develop for the .NET Micro Framework. The SDK includes project templates using Visual C# that you can begin using immediately. In fact, if you use one of the built-in project types, you quickly can build and deploy a sample embedded application. An emulator is provided, so you don't even need a physical device to try it. You can download the SDK.

Once installed, you'll be able to begin developing applications that target ARM-based processors and devices. The best way to see what the SDK does is to jump into a sample application. You can immediately start building an application targeting the included emulator.

Building a .NET Micro Framework Application

After installing the .NET Micro Framework, you will find a new Project Type listed under Visual C#. This is the Micro Framework type shown in Figure 3. You'll see several new templates added within this project type should you select it.

[Framework3.JPG]

Figure 3: New Visual Studio Project types.

To create a sample application, select the Console Application project template within the Micro Framework project types. You then can provide a project Name in the same manner that you do for any other C# project. For my sample code, I use MF_App1. Select OK to create the project in Visual Studio.

If you then open the Program.cs file that was created, you'll see the code in Listing 1 in the editor:

Listing 1: Default Embedded Application

using System;
using Microsoft.SPOT;

namespace MF_App1
{
   public class Program
   {
      public static void Main()
      {
         Debug.Print(
            Resources.GetString(Resources.StringResources.String1));
      }
   }
}

If you click build and run the application (or simply press F5), you should have a successful build, the emulator as shown in Figure 4 should be displayed, and then the program will end. Because your program doesn't do anything more than display a debug message, the program quickly ends and the emulator shuts down. If you want to see the emulator, you can put a break point on the debug line and run the program again.

[Framework4.JPG]

Figure 4: The emulator for a program that does nothing.

A program that does nothing is really not a good illustration. To build a more robust application, you are likely to want to use some of the libraries available. Right-click on your project's name in the Solution Explorer and select the Add References option. Make sure the following libraries are included:

  • Microsoft.SPOT.graphics
  • Microsoft.SPOT.Hardware
  • Microsoft.SPOT.Native
  • Microsoft.SPOT.Net
  • Microsoft.SPOT.TinyCore
  • mscorlib
  • System

Once these references are included, you can begin to build an application that does more.

First, you will want to modify the main() routine that you have in Listing 1. You'll drop the Debug.Print() line and instead do the following:

ButtonWatcher watcher = new ButtonWatcher();
watcher.Run();

Of course, if you are going to call the ButtonWatcher class, you need to add it. You can do this by adding a new class called ButtonWatcher to the project (select Project --> Add New Item --> Class) and then modifying its code to what is in Listing 2.

Listing 2: An Application using buttons on an Embedded Device.

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace MF_App1
{
   enum Button
   {
      None   = -1,
      Left   = Cpu.Pin.GPIO_Pin0,
      Right  = Cpu.Pin.GPIO_Pin1,
      Up     = Cpu.Pin.GPIO_Pin2,
      Select = Cpu.Pin.GPIO_Pin3,
      Down   = Cpu.Pin.GPIO_Pin4
   }

   class ButtonWatcher
   {
      public void Run()
      {
         InputPort up = new InputPort((Cpu.Pin)Button.Up,
            false, Port.ResistorMode.PullUp);
         InputPort down = new InputPort((Cpu.Pin)Button.Down,
            false, Port.ResistorMode.PullUp);
         InputPort left = new InputPort((Cpu.Pin)Button.Left,
            false, Port.ResistorMode.PullUp);
         InputPort right = new InputPort((Cpu.Pin)Button.Right,
            false, Port.ResistorMode.PullUp);
         InputPort select = new InputPort((Cpu.Pin)Button.Select,
            false, Port.ResistorMode.PullUp);

         Button lastButton = Button.None;
         Button currentButton = Button.None;

         while (true)
         {
            if (!up.Read())
               currentButton = Button.Up;
            else if (!down.Read())
               currentButton = Button.Down;
            else if (!left.Read())
               currentButton = Button.Left;
            else if (!right.Read())
               currentButton = Button.Right;
            else if (!select.Read())
               currentButton = Button.Select;
            else
               currentButton = Button.None;

            if (lastButton != currentButton )
            {
               switch (currentButton)
               {
                  case Button.Left:
                     Debug.Print("Left");
                     break;
                  case Button.Right:
                     Debug.Print("Right");
                     break;
                  case Button.Up:
                     Debug.Print("Up");
                     break;
                  case Button.Down:
                     Debug.Print("Down");
                     break;
                  case Button.Select:
                     Debug.Print("Select");
                     break;
               }
               lastButton = currentButton;
            }
            System.Threading.Thread.Sleep(15);
         }
      }
   }
}

This focus of the ButtonWatcher class is to watch the buttons on the embedded device. In Figure 4, you saw that the emulator had five buttons. These can be set up as directional buttons (right, left, up, and down) and a selection button in the center.

In Listing 2, you see that these buttons can be queried by using pin numbers. Rather than using cryptic calls such as Cpu.Pin.GPIO_Pin0 for the buttons, an enumerator called Button is created and the values from the pins are assigned to more intuitive names such as left, right, up, down, and select. This lets you use Button.Left instead of Cpu.Pin.GPIO_Pin0. Of course, you don't have to do this; however, if you do, the rest of your code will be much easier to read!

When the ButtonWatcher's Run method is executed, a number of variables are created; they can be used to watch the buttons. Each is created as an InputPort that is assigned to a given button. These assignments then will let the program do a simple Read() to see whether the button has been clicked. In fact, after setting up the InputPorts and a couple of tracking variables, the program is put into an infinite loop that simply checks each of the InputPort variables to see whether the corresponding button has been clicked. If so, the current button is set to the button that is read. As long as the button is held down, the value of currentButton will be the same as lastButton. Once the button is unselected, all of the reads will be false and therefore the currentButton will be set to None, thus allowing a button to be clicked again or a new button to be selected.

The main purpose of the program is to print out debug messages based on the button that is pressed. If the last button read is not the same as the current one, a debugging message is displayed in Visual Studio's Output window as shown in Figure 5. Instead of doing the debugging message, you could have created programming logic that performed an action when these buttons were pressed.

[Framework5.JPG]

Figure 5: The ButtonWatcher program in action.

It is important to point out that the reason you set the lastButton to the currentButton is to prevent a slew of debug messages to be printed. If you didn't do this, you would get multiple debug messages if you were to hold the button down longer than the Thread sleep value. Granted, the program does a Thread.Sleep() call to slow things down.

You might also be thinking that putting a program into an infinite loop is bad programming practice. If you are creating an embedded application, chances are the program you are creating is all that the device does. As such, when the device is on, the program should be running. A person wouldn't necessarily 'exit' an embedded application.

The .NET Micro Framework: A First Look

The Next Step

This application is still relatively sparse, but knowing how to control the keys sets the stage for doing more elaborate development. Instead of doing a debug message, you could display an X or O on a device that is a dedicated TicTacToe machine. You can do more elaborate functionality as well. For example, to draw an "O," you can call a simple ellipse object:

// draw an 0
m_screenBuffer.DrawEllipse(
   Microsoft.SPOT.Presentation.Media.Color.White,
   (block_width / 2), (block_height / 2),
   ((block_width) / 2) + offset_width,
   ((block_height) / 2) + offset_height);

An "X" is simply drawing a couple of lines in a location on your screen:

// Draw an X
m_screenBuffer.DrawLine(
   Microsoft.SPOT.Presentation.Media.Color.White, 6,
   offset_width, offset_height,
   block_width + offset_width, block_height + offset_height);

m_screenBuffer.DrawLine(
   Microsoft.SPOT.Presentation.Media.Color.White, 6,
   offset_width, offset_height + block_height,
   block_width + offset_width, offset_height);

If you've done a bit of C# programming, nothing should look complex about drawing an O or an X. Rather, it should seem like standard code. And, it is.

Most embedded devices, such as the device EmbeddedFusion provides, come with their own Project items for Visual Studio that give you a good starting point. Such embedded devices might have other features included, such as a sensor to determine whether the device is tilted. In such cases, you can use the provided libraries to tap into the features and thus to do even more interesting applications.

The bottom line is that, once you can control the button and the unique features of the embedded device, if you are using the .NET Micro Framework, most of the coding is basic C#—the same C# you likely have been using on the desktop or on the web.



About the Author

Bradley Jones

Bradley Jones, in addition to managing CodeGuru, Brad! oversees the Developer.com Newtwork of sites including Codeguru, Developer.com, DevX, VBForums, and over a dozen more with a focus on software development and database technologies. His experience includes development in C, C++, VB, some Java, C#, ASP, COBOL, and more as well as having been a developer, consultant, analyst, lead, and much more. His recent books include Teach Yourself the C# Language in 21 Days, Web 2.0 Heroes, and Windows Live Essentials and Services.
Google+ Profile | Linked-In Profile | Facebook Page

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: May 7, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT This eSeminar will explore three popular games engines and how they empower developers to create exciting, graphically rich, and high-performance games for Android® on Intel® Architecture. Join us for a deep dive as experts describe the features, tools, and common challenges using Marmalade, App Game Kit, and Havok game engines, as well as a discussion of the pros and cons of each engine and how they fit into your development …

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds