Thursday, April 21, 2016

How to Fade an LED with PWM in Windows IoT

Motors, dimmable LED's, speakers, multi-color LED's and a variety of other components have a requirement that's easy for an Arduino, but that turns out to be a little tricky in Windows IoT.  This is the second article in a series exploring Windows IoT on a Raspberry Pi.  In this post we'll describe PWM, discuss how to perform simple binary GPIO manipulation, and then dig into configuring a device to fade an LED using Pulse Width Modulation (PWM).

Pulse Width What?

Microcontrollers such as Arduino and System on Chip (SoC) devices such as Raspberry Pi can technically only output one of exactly two voltages on their General Purpose I/O (GPIO) pins: either 0 or 3.3 volts.  The problem is that many components such as speakers or multi-color LED's require not two, but a whole range of voltages.
Microcontrollers or SoC devices typically fulfill the requirement by switching a pin on and off so fast as to give the appearance to most components as being between the min and max.  For instance to get ~3.0 volts you keep the duty cycle, or the proportion of time the pin is at High at 90%.  This process is known as Pulse Width Modulation or PWM.  
The following diagram from Wikipedia is a beautiful illustration of how to accomplish a sine wave using PWM.  Hooking this output up to a speaker would produce a decent sounding continuous tone.
The problem is that PWM can be tricky for devices with non-realtime operating systems, because an OS can't just pause it's pin switching process to do a garbage collection or preemptively give some other process CPU time. Consequently, until recently Microsoft required you to get an external board if you wanted to output variable voltages in its fledgling Windows 10 IoT operating system.
However, as of version 10.0.10586.0 there is a way. That way is called Lightning Providers, but getting it working is a little tricky, and the documentation is scattered and doesn't work out of the box.

Binary GPIO

Before we get into how to do PWM, this series has yet to touch on regular binary GPIO manipulation.  Fortunately it's fairly simple and well documented.  Assuming you've got a hello world Windows IoT app, you can turn a pin high and then low like this:
gpioController = await GpioController.GetDefaultAsync();
if (gpioController == null)
{
    StatusMessage.Text = "There is no GPIO controller on this device.";
    return;
}
_pin = gpioController.OpenPin(22);
_pin.SetDriveMode(GpioPinDriveMode.Output);
_pin.Write(GpioPinValue.High);
await Task.Delay(500);
_pin.Write(GpioPinValue.Low);

Seems simple enough, it flashes an pin (and perhaps an attached LED) High for a half a second.  But there are a couple of things to note.  
First GpioController is in Windows.Devices.Gpio, and it's only available when you reference Windows IoT Extensions for the UWP.

Second, GpioController.GetDefaultAsync() may return null if we're running this Universal Windows Platform project on a regular PC, or a phone, or an XBox.  That's something to guard against.
Third, the pin 22 was (arbitrarily) picked from one of the Pi's available GPIO pins using the following diagram:

In other words, the above code will flash the 8th pin down on the left-hand side (aka the 15th pin).  
Quick word of warning: if you test this out with an LED, make sure you get the polarity right, since LED's are not omnidirectional.

PWM

There are five steps to get PWM working.

1. Latest Bits

First, ensure you have the latest version of Windows IoT.  Technically you only need the current public release of Windows IoT, aka Build 10586, December 2015.  However, I tested this on the Pi 3, and since it's supposed to be 60% faster, your Pi 2 results may vary.  For this reason I'm recommending you install the Insider Preview of Windows IoT, which I showed how to set up in the last post.

2. Lightning Driver

Second, you need to install the Lightning Direct Memory Mapped driver.  Lightning is a new driver that provides a variety of additional capabilities including device and remote board PWM support.  It's still in beta, and consequently there's a warning when you select it: "This option will reduce Windows security in exchange for performance using an in development driver". 
To do change drivers:
  1. Navigate to the configuration url for your device (e.g. http://LeesRasPi3:8080/).  
  2. Select Devices
  3. Under Default Controller Driver, select "Direct Memory Mapped Driver"


  4. Reboot your device when prompted

 Lightning SDK

Third, you'll need to reference the Lightning SDK.  According to the documentation, you just reference via NuGet.  Unfortunately, this doesn't work as of v1.0.3-alpha.  I had to download the Microsoft.IoT.Lightning.Providers C++ source, add the Microsoft.Iot.Lightning.Providers.vcxproj project to my solution, and then make a project reference.  
Incidentally, I contacted some folks at Microsoft, and they said a new nuget will be published shortly with binaries that will fix this issue.

4. Permissions

Next, Lightning providers require additional manifest permissions.  To grant them you'll need to edit the Package.appxmanifest file of your UWP app and add the following bits inside capabilities at the end of the document:
<iot:Capability Name="lowLevelDevices" />
<DeviceCapability Name="109b86ad-f53d-4b76-aa5f-821e2ddf2141"/>
And then add the iot namespace to the Package element at the top of the document and iot to IgnorableNamespaces: 
<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
  IgnorableNamespaces="uap mp iot">

5. PWM Code

Finally, we're ready for some code.  One nice thing is that we can keep all of our existing binary GPIO code, plus allow the device to use either driver by simply adding the following line:
if (LightningProvider.IsLightningEnabled)
{
    LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
}
But, to get full on-device PWM functionality we'll need something like this:
if (LightningProvider.IsLightningEnabled) {
  LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
  var pwmControllers = await PwmController.GetControllersAsync(LightningPwmProvider.GetPwmProvider());
  var pwmController = pwmControllers[1]; // use the on-device controller
  pwmController.SetDesiredFrequency(50); // try to match 50Hz
  _pin = pwmController.OpenPin(22);
  _pin.SetActiveDutyCyclePercentage(.25);
  _pin.Start();
}
The first couple of lines set up the lightning driver and PWM provider using the on-device controller (as opposed to a dedicated PWM board, which you could attach to get better performance).   It then requests a leisurely 50Hz frequency speed.
Finally it opens pin 22 and sets the duty cycle to 25%.  
And that's it!  With a scrollbar and a few extra lines of code you'll be able to get something like this: 


Source Code

The complete code for this project is available on the WindowsIotPwmExample github project.

Summary

In this article we've covered what Pulse Width Modulation is, how to use Windows IoT to write binary-states to GPIO pins, and finally how to generate variable voltages using PWM.  Keep an eye out for the next article in the series on how to turn a Raspberry Pi into an information radiator.

    Tuesday, April 12, 2016

    Getting Started With Windows IoT And Raspberry PI 3

    This is the first post in a series exploring Windows IoT on Raspberry Pi 3.  In this post I'll cover the what and the why of Windows IoT, then show how to install it on a Raspberry Pi 3 and finally how to deploy a first app to it.




    What Is This Thing?


    Windows IoT is a version of Windows 10 designed for small form factor, low cost, Internet connected devices.

    It has three versions.  IoT Core is free, and is the one most people will care about.  It currently works on four devices (three boards):

    • Raspberry Pi 2 (Broadcom BCM2835 )
    • Raspberry Pi 3 (Broadcom BCM2837)
    • Arrow DragonBoard 410c (Qualcomm Snapdragon)
    • MinnowBoard MAX (Intel Atom)

    Windows IoT Core has no shell (e.g. no start menu) and so when running a mouse and keyboard on an LCD feels like a single app version of Windows.  Otherwise this free operating system has no limitations.  You can take a product to market on hundreds of thousands of devices and pay absolutely nothing for the OS.

    IoT Enterprise and Mobile Enterprise, aren't free.  They're more for ATM or Point of Sale scenarios.  IoT Mobile Enterprise uses a "modern shell" like a windows phone.  IoT Enterprise additionally work on x64 and larger devices and uses a "desktop shell" like traditional Windows 10.  They also allow system administrators to defer system updates.

    Windows, Seriously?


    There are a lot of options if you're looking to build a device that interacts with the real world. Arduino, for instance, is a fantastic choice if there's a chance you'll ever mass produce your thing, since you can find ATMEL chips that cost less than $2 and the ecosystem and set of libraries is huge. Also your thing will run faster (realtime even) without the overhead of an operating system.

    However, if your thing will require:

    • Multitasking (e.g. serving up web pages),
    • Running USB peripherals,
    • Displaying on an LCD screen, or
    • Connecting to the Internet

    Then one of the boards listed above may be a better choice.  But why not just run Linux?

    Security is one benefit.  For one thing you get automatic updates to help patch future vulnerabilities.  There's also Native UEFI , which helps protect against malware at the firmware and driver level.  There's Trusted Platform Module (TPM) support, which helps move cryptography operations to the hardware level.  Identity protection and access control may be important if you're running a kiosk that multiple people could log on to.  And there's even support for BitLocker and Enterprise Data Protection if things like encryption at rest, auditing, or remote device wiping matter to you.

    For another thing Windows IoT makes it easy to connect with other devices and services.  You can, for example easily and securely connect to Azure IoT Hub which can theoretically aggregate data from millions of devices in realtime.  It also has built in support AllJoyn, which is a way of connecting to other IoT devices.

    But one of the biggest benefits is the Windows ecosystem.  You build apps for it with Visual Studio, which is top notch IDE.  You can port existing Win32 or .Net applications to Windows IoT far more easily than to Linux.  You get remote desktop.  You can write in C#, Python, JavaScript, or Arduino C, and even embed Arduino libraries.  If you have experience building .Net apps, then the learning curve is extremely low.  And finally if you want your app to additionally target large screens, tablets, phones, and even XBox, then Windows IoT is your only option, because Windows IoT is designed to run Universal Windows Platform apps.

    Device Setup


    If you don't already have a Raspberry Pi 3, pick up one of the many good kits that includes an adequate power supply (outputs at least 1 Amp, 2 is better), a fast Micro SD card, and perhaps a case.

    Once you have a device you'll need to set it up with the Windows IoT operating system.  As of this writing, the official release is Build 10586, December 2015.  Unfortunately, this version doesn't work with Raspberry Pi 3.  Consequently, you'll need the Insider Preview of Windows IoT.

    To set a new Raspberry Pi 3 device follow the Insider Preview Setup Instructions (or if they've RTM'd, download the Core IoT Dashboard).  You'll download an image (Build 14295 supports remote desktop) and use the IoT Dashboard app to flash the image to an SD card.




    Now you can put the SD Card into your Raspberry Pi, plug an HDMI cable into a monitor, and attach power via micro USB.  If all goes well you should see Windows loading up.



    Once it's loaded up it will start the default app, which provides a place for basic device configuration.



    Before you can go much further you need to set up Internet access.  You can do that most easily via  Ethernet cable or approved WiFi device (careful, the list isn't big), and power it on.

    But wait, doesn't Raspberry Pi 3 have build-in WiFi?  Unfortunately, that isn't supported in the current build.  Hopefully it will be in there soon.

    Once you have the device on the network you'll have a much more robust set of options for accessing it.  You can, for instance, get in through PowerShell.

    Or better, when you go to Devices in the IoT Dashboard app, your device should be listed.  If you click the web link you can access the snazzy web browser interface.  This might be a good time to change the device name and password.


    Build Environment Setup


    Great, now you've got an Internet connected mini PC with no software.  To write apps for it you'll need to set up a "real" PC with Visual Studio.

    To set up your PC to build apps for Windows IoT you need Visual Studio 2015 Update 1 or better (any edition).  Be careful, when doing so you need to select the "Universal Windows App Development Tools" feature or else you'll get the ever helpful

    Error: this template attempted to load component assembly 
    'Microsoft.VisualStudio.Universal.TemplateWizards, Version=14.0.0.0, 
    Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. For more information 
    on this problem and how to enable this template, please see documentation 
    on Customizing Project Templates.

    Next, install the Windows IoT Core Project Templates.  Restart Visual Studio.

    Finally, enable developer mode to enable installing store apps via Settings, Updates & Security -> For Developers -> Developer mode

    Hello World


    To create a hello world app:
    1. File -> New -> Project
    2. Blank App (Universal Windows)

      1-NewProject.png


    3. Add a reference to the Windows IoT extension SDK

    4. Update MainPage.xaml with some XAML like

      <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Hello World</TextBlock>

    5. Under solution Platform Select: Arm
    6. For Device Configuration Select Remote Machine



    7. In the resulting dialog type the name of your device



    8. Hit F5!
    Once you've done that try putting a button on the screen, setting breakpoints, inspecting variables.  You'll find it's the exact same experience you've come to love in other Visual Studio projects, just in a small, inexpensive form factor.

    Summary


    This post has covered the what and why of Windows IoT as well as how to configure a Raspberry Pi 3 for Windows IoT and deploy a very simple application to it.  The next post in the series will cover how to control pins, and how to run a simple motor.


    Lee_-71-square-150px.jpgLee Richardson is a senior software developer at Inferno Red with a passion for .Net development, open source software, continuous integration, building cross platform mobile apps, and hardware hacking. In his spare time he runs Siren of Shame.  He has been consulting in the Washington DC area for over 17 years.  Keep up with him @lprichar.