(note: these steps are loosely based on instructions from http://adeneo-embedded.blogspot.ca/2009/01/using-interop-in-net-micro-framework.html )

You may skip this step if you simply want to download the pre-compiled firmware files I've provided in the download page.
The next steps are to create the method signature for your function. We need the signature (think of function prototypes) of the method so that the C# code can call on the native function. I recommend that this is done inside a public static class as a static method. Do this in an entire separate project (use the project template for a .NET Micro Framework static library). My project is named "NeoPixelNative" and the only file inside is "NeoPixelNative.cs", see code below:
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace NeoPixel
    public static class NeoPixelNative
        /// <summary>
        /// This is the interop call to the low level native C++ code that resides in the modified firmware
        /// The firmware must contain the NeoPixel low level native C++ code
        /// This method is "internal" so that NeoPixelChain may access it
        /// </summary>
        /// <param name="dataPtr">array of bytes already organized in the GRB format, ready to be sent to all the NeoPixels</param>
        /// <param name="count">the number of NeoPixels</param>
        /// <param name="pin">The Cpu.Pin representation of which MCU pin the first NeoPixel's data input pin is connected to</param>
        public extern static void Write(byte[] dataPtr, int count, UInt32 pin);
The line "[MethodImpl(MethodImplOptions.InternalCall)]" is an attribute that tells the compiler that the function is internal to the firmware.

(note: only a few data types are supported for the parameters, don't go too crazy, try to pass in only basic data types)

You also need to go into the project properties, look for the ".NET Micro Framework" tab, and check the "Generate native stubs for internal methods" checkbox. Give it the stub a root name (I used "NeoPixel" as the root name) and remember the path (which should be inside your project directory).

Once all these steps are done, build the project. The stubs should be generated. The files you should see are:
  • dotNetMF.proj
  • NeoPixel_NeoPixel_NeoPixelNative.h
  • NeoPixel.cpp
  • NeoPixel_NeoPixel_NeoPixelNative_mshl.cpp
  • NeoPixel.h
  • NeoPixelNative.featureproj
  • NeoPixel_NeoPixel_NeoPixelNative.cpp
Remember that "dotNetMF.proj" keeps track of which files are compiled by the C or C++ compiler, while "NeoPixelNative.featureproj" creates the relationship between native code and C#.

(note: this means that for other projects, if at anytime you want to add in another C or C++ code file, edit the "dotNetMF.proj" file)

Edit the "NeoPixelNative.featureproj" file to change the paths involved. See below (the commented XML tags are what they used to be)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Description><Add Feature Description Here></Description>
    <Groups ></Groups>
    <DriverLibs Include="NeoPixelNative.$(LIB_EXT)" ></DriverLibs>
    <InteropFeature Include="NeoPixelNative" ></InteropFeature>
    <!-- <MMP_DAT_CreateDatabase Include="$(BUILD_TREE_CLIENT)\pe\$(ENDIANNESS)\NeoPixelNative.pe" ></MMP_DAT_CreateDatabase> -->
    <MMP_DAT_CreateDatabase Include="$(SPOCLIENT)\Solutions\NetduinoPlus2\ManagedCode\NeoPixelNative\bin\Debug\le\NeoPixelNative.pe" ></MMP_DAT_CreateDatabase>
    <!-- <RequiredProjects Include="C:\Projects\netduinoplus2\projects\NeoPixel\NeoPixelNative\Stubs\dotnetmf.proj" ></RequiredProjects> -->
    <RequiredProjects Include="$(SPOCLIENT)\Solutions\NetduinoPlus2\DeviceCode\NeoPixelNative\dotNetMF.proj" ></RequiredProjects>
I also added two files to the "dotNetMF.proj" file, I added "NeoPixel_NativeCode.cpp" and "NeoPixel_NativeCode.h", see below:
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Settings" ></Import>
<HFile Include="NeoPixel.h" ></HFile>
<Compile Include="NeoPixel.cpp" ></Compile>
<Compile Include="NeoPixel_NeoPixel_NeoPixelNative.cpp" ></Compile>
<HFile Include="NeoPixel_NeoPixel_NeoPixelNative.h" ></HFile>
<Compile Include="NeoPixel_NeoPixel_NeoPixelNative_mshl.cpp" ></Compile>
<HFile Include="NeoPixel_NeoPixel_NeoPixelNative.h" ></HFile>
<Compile Include="NeoPixel_NativeCode.cpp" ></Compile>
<HFile Include="NeoPixel_NativeCode.h" ></HFile>
<Import Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Targets" ></Import>
I have already created and fully written the new CPP and H files inside the same directory.

Copy the stubs over to "$(SPOCLIENT)\Solutions\NetduinoPlus2\DeviceCode\NeoPixelNative\". "$(SPOCLIENT)" represents where you put your porting kit.

Now look inside your project folder again, look for a folder "projectfolder\NeoPixelNative\bin\Debug\le\" and inside there will be a file "NeoPixelNative.pe". Just make sure it's there. Copy the entire "projectfolder\NeoPixelNative\bin\" into "$(SPOCLIENT)\Solutions\NetduinoPlus2\ManagedCode\NeoPixelNative\bin\"

Then you need to find "......\Solutions\NetduinoPlus2\TinyCLR\TinyCLR.proj", edit it. Add the line
<Import Project="$(SPOCLIENT)\Solutions\NetduinoPlus2\DeviceCode\NeoPixelNative\NeoPixelNative.featureproj" />
<Import Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Interop.Settings" />
and then add
    <RequiredProjects Include="$(SPOCLIENT)\Solutions\NetduinoPlus2\DeviceCode\NeoPixelNative\dotNetMF.proj" ></RequiredProjects>
    <DriverLibs Include="NeoPixelNative.$(LIB_EXT)" ></DriverLibs>
<Import Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Targets" />

Bonus: enable bitmaps and other graphical features

Netduino's firmware does not actually support graphical features, if you tried to even create a bitmap object, it will throw a nasty "NotSupportedException".

The .NET Micro Framework does have some pretty cool graphical features but the Netduino does not include them in order to save some space. I've modified our "dotNetMF.proj" file to include some of these features, by adding
  <Import Condition="'$(PLATFORM_EMULATED_FLOATINGPOINT)'=='true'" Project="$(SPOCLIENT)\Framework\Features\NEED_FLOATING_POINT" />
  <Import Project="$(SPOCLIENT)\Framework\Features\Graphics_PAL.libcatproj" />
  <Import Project="$(SPOCLIENT)\Framework\Features\Graphics_BMP_CLR.libcatproj" />
  <Import Project="$(SPOCLIENT)\Framework\Features\Graphics_Gif_CLR.libcatproj" />
  <Import Project="$(SPOCLIENT)\Framework\Features\Graphics_JPG_CLR.libcatproj" />
  <Import Project="$(SPOCLIENT)\Framework\Features\Graphics_CLR.libcatproj" />
  <Import Project="$(SPOCLIENT)\Framework\Features\SPOT_Graphics_CLR.libcatproj" />
    <PlatformIndependentLibs Include="SPOT_Graphics.$(LIB_EXT)" />
    <RequiredProjects Include="$(SPOCLIENT)\CLR\Libraries\SPOT_Graphics\dotnetmf.proj" />
    <PlatformIndependentLibs Include="Graphics.$(LIB_EXT)" />
    <RequiredProjects Include="$(SPOCLIENT)\CLR\Graphics\dotnetmf.proj" />
    <PlatformIndependentLibs Include="Graphics_BMP.$(LIB_EXT)" />
    <RequiredProjects Include="$(SPOCLIENT)\CLR\Graphics\Bmp\dotnetmf.proj" />
    <PlatformIndependentLibs Include="Graphics_JPEG.$(LIB_EXT)" />
    <RequiredProjects Include="$(SPOCLIENT)\CLR\Graphics\Jpeg\dotnetmf.proj" />
    <PlatformIndependentLibs Include="Graphics_GIF.$(LIB_EXT)" />
    <RequiredProjects Include="$(SPOCLIENT)\CLR\Graphics\Gif\dotnetmf.proj" />
    <DriverLibs Include="Graphics_pal.$(LIB_EXT)" />
    <RequiredProjects Include="$(SPOCLIENT)\DeviceCode\pal\graphics\dotNetMF.proj" />
There are plenty of other features within .NET Micro Framework that is not included in the Netduino firmware. I hope this gives you a clue on how to include new features.

Although, you are supposed to add those items to "TinyCLR.proj" instead, but I added them to NeoPixelNative's own "dotNetMF.proj" because I wanted to make my edits to the firmware less intrusive.

This guide was first published on Sep 12, 2013. It was last updated on Sep 12, 2013.

This page (Preparing Custom Firmware) was last updated on Sep 06, 2013.

Text editor powered by tinymce.