Digital IO

Digital IO is often referred to as General Purpose, Input/Output or GPIO.

Digital ports can be set to be HIGH (powered at 3.3V), or LOW (grounded at 0V) which correspond to digital 1 and 0, respectively.

Digital Outputs

Setting the state of a Digital Output is done using an implementation of the IDigitalOutputPort interface. Using the static Device property of your application’s entry class App<D,A> is the simplest way to create an instance.

For example, if you wanted to be able to control the state of the D05 pin on the F7 Meadow, you could use the following code to create an instance of the IDigitalOutputPort with an initial state of LOW:

var output = Device.CreateDigitalOutputPort(
    Device.Pins.D05, false);

You could then assert a state on the pin to LOW or HIGH using one of the following:

output.State = false;   // assert LOW
output.State = true;    // assert HIGH

Digital Inputs

Reading the state of a Digital Input is done using an implementation of the IDigitalInputPort interface. Using the static Device property of your application’s entry class App<D,A> is the simplest way to create an instance.

For example, if you wanted to be able to read the state of the D03 pin on the F7 Meadow, you could use the following code to create an instance of the IDigitalOutputPort with an initial state of LOW:

var input = Device.CreateDigitalInputPort(
    Device.Pins.D03);

Optional constructor parameters allow you to set the internal resistor mode, interrupt mode, debounce and glitch filter behavior.

To poll the state of the input, you read the State property:

var currentState = input.State;

Interrupts

Interrupts allow your application to be notified of the change of state of a Digital Input without having to poll the value. Enabling interrupts requires two things from your application: setting the InterruptMode of the IDigitalInputPort instance and then adding a handler for the instance’s Changed event.

For example, if you wanted your application to get notified when the D03 input pin changed from LOW to HIGH (a rising interrupt), you could use the following code:

// create the InputPort with interrupts enabled
var input = Device.CreateDigitalInputPort(
    Device.Pins.D03,
    InterruptMode.EdgeRising);

// add an event handler
input.Changed += (s, e) =>
{
    Console.WriteLine($"interrupt occurred");
};

Timing

NOTE FROM THE WILDERNESS LABS TEAM:

These timing values are measurements from Beta 3.6. We recognize that they are not fast enough for all applications, but they are adequate for many. Keep in mind that these values are a significant improvement from earlier Betas and the expectation is for them to improve drastically as we move toward release, so if they don’t meet your needs feel free to contact us with your requirements to find our when to expect a release that will meet your needs.

An important consideration for most applications is the minimum timing capabilities of the platform on which you’re running.

Keep in mind that Meadow is running .NET and is therefore not a deterministic, real-time system. These values are representative numbers, but system behaviors like memory allocation and garbage collection could occasionally yield much larger values.

Some basic timing measurements and expectations are as follows:

Minimum Output Transition Time: ~4ms

How fast can the platform cycle a simple digital output? The following test, measured with an oscilloscope, shows that the line has a 50% duty cycle, with each HIGH and LOW state maintained for approximately 4.1ms:

var d04 = Device.CreateDigitalOutputPort(Device.Pins.D04);

while (true)
{
    _d04.State = true;
    _d04.State = false;
}

Minimum Interrupt Service Time: ~50ms

Given an incoming interrupt, how fact can the platform react and execute some handler? The following test, measured with an oscilloscope, shows that the time from the rising input edge to the rising output edge to be approximately 50ms:

var input = Device.CreateDigitalInputPort(
    Device.Pins.D03,
    InterruptMode.EdgeRising);
            
var output = Device.CreateDigitalOutputPort(
    Device.Pins.D05, false);

input.Changed += async (s, o) =>
{
    output.State = true;
    await Task.Delay(1000);
    output.State = false;
    Console.WriteLine($"click");
};

IMPORTANT NOTE:

Interrupt debounce behavior currently (Beta 3.6) can be confusing. The debounce is currently being done in the managed code of the DigitalInputPort and is therefore subject to the performance limitations of interpreted code execution. A good example is this:

Assume you have a DigitalInputInputPortt with a debounce duration of 10ms. Now assume you get two interrupts 10us (not ms) apart.

On the surface, you’d expect your application to only receive one interrupt as the debounce duration is much larger than the time between interrupts, however it is very likely that your application will receive two interrupt events.

The reason for this is that the underlying OS is detecting both interrupts and sending them upstream to the managed code, but the DigitalInputPort itself is executing the handling of those interrupts much slower, so its measurement between handling the events from the OS is actually greater than the 10ms debounce duration.

We will be addressing this behavior in a future release, but for safety and sanity, applications should take this behavior into account. We recommend a debounce of at least 50ms to minimize these unwanted interrupts.

Pulse-Width-Modulation PWM

Digital output ports can be used to generate a Pulse-Width-Modulation (PWM) signal, which approximates an intermediate voltage between LOW or HIGH by switching between ON and OFF very quickly:

PWM signals are frequently used to control the brightness of LEDs, as well as serve as the control signal for precision motors such as servos and stepper motors.

Communication Protocols

Digital IO also includes built-in support for a host of different types of common digital communication protocols including:

  • I2C
  • SPI (Serial Peripheral Interface)
  • UART (Serial)
  • CAN
  • I2S (Integrated Inter-IC Sound Bus)

 


These docs are open source. If you find an issue, please file a bug, or send us a pull request. And if you want to contribute, we'd love that too!