1

Windows 10 IoT doesn't support use of the PWM functionality of Raspberry Pi 2. So, as a workaround, I'm planning on using a GPIO pin and just toggling it from High to Low REALLY FAST to achieve the frequency that I desire. In this case around 40Khz..

So, is it safe to toggle a GPIO pin from high to low 40,000 times per second?

WITHOUT breaking my Raspberry Pi 2?

I plan on doing this in 1 second long bursts, but wonder what the side effects would be if I ran it like that constantly.

UPDATE------ Well, I gave it a shot and it seems to be working. Here is some code that you can use if you would like to use a GPIO pin to act like a PWM pin (kinda...)

Basically call the constructor on this class and pass it a frequency in hz and the GPIO number you would like to use. When you're ready to generate the frequency, just call Activate() and pass it the number of milliseconds you would like it to run at the specified frequency.

Enjoy:

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
using Windows.Devices.Pwm;

namespace DownDoggie
{
    public sealed class PWM : IDisposable
    {
        private int Pin { get; set; }
        private double MicrosecondDelay { get; set; }
        private GpioPin GpioPin { get; set; }
        private PwmPin Pwm { get; set; }
        private int Frequency { get; set; }
        public PWM(int frequency, int pin)
        {
            Pin = pin;
            Frequency = frequency;
            MicrosecondDelay = 1000000d/Frequency/2;
            Initialize();
        }

        private async void Initialize()
        {
            var pwmController = await PwmController.GetDefaultAsync();

            if (pwmController != null)
            {
                pwmController.SetDesiredFrequency(Frequency);
                Pwm = pwmController.OpenPin(Pin);
                if (Pwm != null)
                {
                    Pwm.Polarity = PwmPulsePolarity.ActiveLow;
                    Pwm.SetActiveDutyCyclePercentage(50);
                }
                else
                {
                    Debug.WriteLine($"ERROR !!!  Could not OpenPin({Pin}) for Pwm");
                }
            }
            else
            {
                var gpio = await GpioController.GetDefaultAsync();
                Debug.WriteLine($"Opening Pin {Pin}");
                GpioPin tempPin;
                GpioOpenStatus status;
                if (gpio.TryOpenPin(Pin, GpioSharingMode.Exclusive, out tempPin, out status))
                {
                    GpioPin = tempPin;
                    Debug.WriteLine($"Opened GpioPin({Pin})  Status= {status}");
                    GpioPin.SetDriveMode(GpioPinDriveMode.Output);
                    GpioPin.Write(GpioPinValue.High);
                }
                else
                {
                    Debug.WriteLine($"Couldn't open GpioPin({Pin})  Status= {status}");
                }
            }
        }

        public async void Activate(int durationMilliseconds)
        {
            if (Pwm != null)
            {
                Pwm.Start();
                Sleep(durationMilliseconds);
                Pwm.Stop();
            }
            else if(GpioPin != null)
            {
                DateTime stopTime = DateTime.Now.AddMilliseconds(durationMilliseconds);

                while (stopTime > DateTime.Now)
                {
                    GpioPin.Write(GpioPinValue.Low);
                    await DelayMicroSeconds(MicrosecondDelay);
                    GpioPin.Write(GpioPinValue.High);
                    await DelayMicroSeconds(MicrosecondDelay);
                }
            }
            else
            {
                Debug.WriteLine($"ERROR !!!  Could not Activate({Pin}) Pwm and GpioPin are both null.");
            }
        }

        public void Dispose()
        {
            if (Pwm != null)
            {
                if (Pwm.IsStarted)
                {
                    Pwm.Stop();
                }
                Pwm.Dispose();
                Pwm = null;
            }
        }

        public void Sleep(int milliseconds)
        {
            SpinWait.SpinUntil(() => false, milliseconds);
        }

        /// <summary>
        /// Delays the current thread by the given number of μs.
        /// </summary>
        /// <param name="delayMicroseconds">The number of μs to delay the thread.</param>
        /// <returns>Returns an awaitable Task instance.</returns>
        private async Task DelayMicroSeconds(double delayMicroseconds)
        {
            TimeSpan delay = TimeSpan.FromTicks(10 * (int)delayMicroseconds);
            await Task.Delay(delay);
        }

    }
}
  • There's a preview SDK here that reportedly includes a PWMController class. May be worth investigating. – goobering Feb 12 '16 at 6:35
2

WITHOUT breaking my Raspberry Pi 2?

I'm not a Win IoT user, but I can't possibly see how this would damage anything (of course this may depend what the pin is attached to). That it will work sufficiently well is another matter. I've fooled around dimming LEDs this way and it works for that but not nearly as well as using the PWM clock (they flicker intermittently, and that it is at much less than 40 KHz).

I don't know if windows allows for direct mapping of kernel/system memory. If so and you understand C and POSIX mmap(), you could start here then look at one of the linux library sources.

Sooner or latter someone will get around to a proper solution.

  • Also, there is no guarantee it will be 40Khz, always on each cycle. From what I have read somewhere PWN is really slow on IoT at the moment. – Piotr Kula Feb 12 '16 at 7:56
  • I know windows has some special "real time" priorities; if you set it as high as you can and make sure nothing else is happening it might works a high percentage of the time but you are right, it won't be perfectly consistent. I think generally devices that ask you for a clock pulse expect and require a clock pulse -- they are hardware timed, you need hardware timing too. To do this properly you have be able to directly divide a signal from that PWM clock. – goldilocks Feb 12 '16 at 14:32
  • 1
    Fm transmission out of a gpio pin waggles the pin up and down stably at about 100MHz using DMA. Probably overkill here, but worth knowing about. – lwr20 Feb 13 '16 at 9:31
  • This is what I mean by "allowed access to system memory". The kernel controls the hardware. Linux will allow direct access to it through, e.g., back doors like /dev/mem, but it does not have to do that and I don't know if windows does. If it it does not, you cannot just choose to do so because you want to without going the proper route (device driver). You can toggle a pin very quickly from userspace without that just using a timer, etc., but it will not be reliable beyond say ms granularity on a multi-tasking OS. – goldilocks Feb 13 '16 at 12:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.