Hardware IO

Lots of projects require access to the special IO features on the Raspberry Pi. In this article, I will talk about working with GPIO.

There are many libraries that work with C#, to access to the Hardware IO. Each of these libraries has its own approach. There are no common properties or methods in these libraries. Even the pin number could be named differently.

I have not gone through extensive studies on these libraries. Not sure if there is one library that covers all the features needed by all programs. (I kind of doubt that.)

Adapter Design Pattern

For your programs to work properly, I strongly suggest that you add one more layer to the modules. Much like an Adapter design pattern. Which means your main program will call Adapter class to do work. The Adapter class will call the library to do the actual work. There are many benefits in this design, to name a few:

  • The dependency on a single library is lifted. You can switch to other libraries without changing your main program.
  • You get to decide how to name (or number) the pins. Let the Adapter class do the translation.
  • If one library can not meet all your requirements, you can add or switch to a new library. Your main program will not need to change.
  • It’s easier to mock unit test programs with your own Interface. You will probably need to use an Interface for the purpose of unit test anyway.

Access Privilege

Access to the hardware requires super user privilege. To run the program in command line, use sudo mono program-path. In the case of HelloWorld, the full program path is /home/pi/Projects/HelloWorldSulution/HelloWorld/bin/Debug/HelloWorld.exe. For production programs, most likely, you would copy the compiled objects to a different library.

Debugging

To debug the program in MonoDevelop, it could be an issue. By default, MonoDevelop is run under user’s privilege. The program will fail to debug, if hardware IO is involved. I have done lots of research, but couldn’t find a clean solution. That leaves me but few options.

  • Compile, then test the program with command sudo mono program-path. This is my least favorite approach. This is more like integration test than debugging.
  • Compile, but don’t run debug on the main program. Debug with unit test modules. Mock the part that calls for hardware IO. Run your program only for integration test (under super user privilege).
  • Run MonoDevelop with super user privilege. You can do this by changing the command when launch MonoDevelop. Beware! The objects created during the session will be owned by super user. Do it at your own risk.

Packages

Among the packages available, I would like to recommend the Raspberry.IO and Unosquare sets.

Raspberry.IO

There are three related packages in this set.

  • Raspberry.IO.GeneralPurpose3
  • Raspberry.IO.InterIntegratedCircuit3
  • Raspberry.IO.SerialPeripheralInterface3

For detail, visit Project Web Site.

These packages can be installed with NuGet easily.

Pick the ones you need, click Add Packages to install.

Note: Do not use earlier versions, use the ones with “3” as suffix.

Sample code segment that makes LED blink:

using Raspberry.IO.GeneralPurpose;

...

var led1 = ConnectorPin.P1Pin11.Output();
var connection = new GpioConnection(led1);

for (int i = 0; i < 10; i++) 
{
    connection.Toggle(led1);
    System.Threading.Thread.Sleep(100);
}

connection.Close();

Unosquare

There are two related packages in this set.

  • Unosquare.Raspberry.IO
  • Unosquare.RaspberryIO.Peripherals

For detail, visit Project Web Site.

These packages can be installed with NuGet.

Sample code segment that makes LED blink:

using Unosquare.RaspberryIO;

...

var pin = Pi.Gpio.Pin00;
pin.PinMode = Unosquare.RaspberryIO.Gpio.GpioPinDriveMode.Output;
bool turnOn = true;

for (int i = 0; i < 3; i++) {
    pin.Write (turnOn);
    turnOn = !turnOn;
    System.Threading.Thread.Sleep (1000);
}

pin.Write (false);