20 February 2015

Controlling a LED with a Raspberry PI 2 using Mono and C#

My fellow MVP Peter Nowak from Germany pointed me to this awesome kit on Amazon.de that has this vast array of sensors in it.

It comes with 37 sensors and peripherals that can be controlled with a Raspberry PI2. It’s originally made for the PI B+, but as this is pin compatible with the PI 2 this works fine. It comes with a mini CD with sample code, but unfortunately this is all C - you need to compile it using GCC. Not having programmed in C since the late 90’s, it’s not code I feel very comfortable messing around with. On the other hand, I am also to impatient to let this gather dust until Windows 10 for devices becomes available.

Now the code samples in C that go with this kit all use a library called wiringPI, that is created by one Gordon Henderson. I basically used this library as a foundation for getting the stuff to work with C#. You first have to install the library. Gordon has a simple step-by-step manual on how to go about on this. Simply open a console, go to the directory where you want to download the library’s sources to, and follow his instructions.”Installing” in Linux apparently means installing git, clone the repository, and start a build file that apparently compiles the whole shebang and puts it ‘somewhere’. The net result is that you can compile the sample C programs that comes with the kit using Gordon’s library to control the sensors.

Then there is this guy, Daniel Riches, who has created a simple wrapper library for C#. How this works is mind-bogglingly simple – he simple uses DllImport to wrap calls to the C library and making those accessible to C#. I haven’t seen this technique used in anger since 1999, in a Visual Basic 6 project. But apparently this still works – and what’s more important – it apparently works under Mono too, even if the imported code does not come from a DLL at all, but a ‘so’ file.

He kind of describes what you need to do – after installing Gordon’s library, you go (still on the command line of course) to the subfolder “wiringPi” of the folder where you have started the build, and then start three commands to create ‘shared libraries’:

cc -shared wiringPi.o -o libwiringPi.so
cc -shared wiringPiI2C.o -o libwiringPiI2C.so
cc -shared wiringPiSPI.o -o libwiringPiSPI.so

And apparently you can then just delete the folder where you have downloaded wiringPi’s sources in. The library is installed and can be used.

Now Daniel’s sample shows the way, unfortunately it’s missing one key feature for my goal – for controlling a LED you will need access to the “softPwm” routines of wiringPi. Browsing the C sources I found the softPwm.c file with the routines I needed to access. So I created my own wrapper class:

using System.Runtime.InteropServices;

namespace WiringPi
{
  public class SoftPwm
  {
    [DllImport("libwiringPi.so", EntryPoint = "softPwmCreate")]
    public static extern void Create(int pin, int initialValue, int pwmRange);

    [DllImport("libwiringPi.so", EntryPoint = "softPwmWrite")]
    public static extern void Write(int pin, int value);

    [DllImport("libwiringPi.so", EntryPoint = "softPwmStop")]
    public static extern void Stop(int pin);
  }
}

As you see, this is all pretty ugly – everything is public static, it follows the layout of the original code very closely and is in its current for totally not object oriented. But whatever, it’s still early days and it’s a temporary measure until Windows 10 pops up anyway. What this does is make a few C routines accessible to C# – for instance, the C routine “softPwmWrite”, that puts a value on a GPIO pin, becomes available al SoftPwm.Write.

And then I can write the following simple program that lets the multi color LED that comes with the SunFounder kit it all kinds of colors:

using System;
using System.Threading;
using WiringPi;

namespace SunfounderTest
{
  class Program
  {
    const int LedPinRed = 0;
    const int LedPinGreen = 1;
    const int LedPinBlue = 2;

    static void Main(string[] args)
    {
      if (Init.WiringPiSetup() != -1)
      {
        SoftPwm.Create(LedPinRed, 0, 100);
        SoftPwm.Create(LedPinGreen, 0, 100);
        SoftPwm.Create(LedPinBlue, 0, 100);
        Console.WriteLine("Init succeeded");

        for (var i = 1; i < 3; i++)
        {
          ShowColor(255, 0, 0, "Red");
          ShowColor(0, 255, 0, "Green");
          ShowColor(0, 0, 255, "Blue");
          ShowColor(255, 255, 0, "Yellow");
          ShowColor(255, 0, 255, "Pink");
          ShowColor(0, 255, 255, "Cyan");
          ShowColor(195, 0, 255, "Purple");
          ShowColor(255, 255, 255, "White");
        }

        SoftPwm.Stop(LedPinRed);
        SoftPwm.Stop(LedPinGreen);
        SoftPwm.Stop(LedPinBlue);
      }
      else
      {
        Console.WriteLine("Init failed");
      }
    }

    private static void ShowColor(int r, int g, int b, string label)
    {
      SetLedColor(r, g, b);
      Console.WriteLine(label);
      Thread.Sleep(1000);
    }

    private static void SetLedColor(int r, int g, int b)
    {
      SoftPwm.Write(LedPinRed, r);
      SoftPwm.Write(LedPinGreen, g);
      SoftPwm.Write(LedPinBlue, b);
    }
  }
}

I will not even begin with pretending that I actually fully understand what I am doing – and I even understand less of the why - but you first have to call the Init.WiringPiSetup method – that was already wrapped by Daniel – and then you need to call ‘Create’ on the three pins - only then you can actual set value to the pins using SoftPwm.Write. I wrapped the calls to that in SetLedColor that accepts red, green and blue values (apparenly 0-255), which is in turn wrapped in a routine that writes progress info and waits a little before progressing. And at the end, you will need to call Stop on all three pins to make the LED go off again, or else it will happily stay on.

Net effect: if you connect LED Pin R to GPIO17, Pin G to 18, Pin B to 27 and the ground pin to on of the GND, the led will flash trough a whole range of colors.

LED controlled by C# on Raspberry PI2 using C#

It will only work if you run the app using sudo, so

sudo mono SunfounderTest.exe

The annoying part is that in the samples provide with this kit these pins 17, 18 and 27 are referred to as 0, 1 and 2. This apparently has historical reasons. On this page at element14 I have found a pin schema with translation from one naming to the other. Notice Pin number 11 is called both GPIO17 as well as GPIO_GEN0. This correspond to Pin 0 in the code. I assume there is some logic somewhere, but I yet have to discover that :)

As is my custom, you can find a demo solution here. Mind you – not all of the code is mine, part of it is from Daniel Riches

5 comments:

Anonymous said...

That remember us the old times, on serial, parallel and usb communication c program to led blink or meassure. Nice to see it again with more color LEDs.
Advantage wold be to use solar panel and LED shows, day and night play.
COM1 send 2* power 5v, and parallel for 8 channels :)

Unknown said...

I'm just getting an Entry Point Not Found Exception whenever I try and use this.
Any ideas?
using a rpi B+

Joost van Schaik said...

@Tim unfortunately I have not. I am using a different device, and I have moved away from Raspbian and Mono as soon as Windows 10 CoreIoT became publicly available, so I have not been following this line of technology anymore.

Unknown said...

Hi. Where you compile this program? in Windows or on RPI? and what kind command mono you use?

Joost van Schaik said...

Hi Бойков Александр ;)

Here http://dotnetbyexample.blogspot.nl/2015/02/starting-owin-aspnet-server-on.html you can see how I installed mono, follow the link to Jan Tielens' blog. Compilation actually takes place on Windows, you then have to copy it over to Raspberry PI2 using a SSH I think. I don't quite remember that last part. Save yourself some trouble and install Windows 10 IoT Core, like I did ;)