Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

PwmGamma Sample


  • Please log in to reply
4 replies to this topic

#1 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 18 August 2010 - 08:50 AM

As a follow-up to the PwmSample, CW2 suggested extending it to address the non-linear response of the LED.

After a bit of research, I found that this is referred to as "gamma correction", and even found an application note that discusses using gamma correction with PWM:

http://www.maxim-ic....dex.mvp/id/3667

So, here's an update to PwmSample that uses a pre-computed LUT (lookup table) for the PWM output values. These are the gamma-corrected values (for gamma = 2.5) that produce a brightness ramp that looks linear (more or less) to our eye.

Here's the code:
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace PwmGamma
{
    public class Program
    {
        const int pwmPeriod = 50;

        // Lookup table for the LED brightness.  The table contains the 
        // gamma-corrected values (for gamma = 2.5).  This approximates
        // a linear increase in the perceived brightness.
        static uint[] gammaTable = {
             0,  0,  0,  0,  1,  1,  1,  2,  2,   3,
             4,  5,  6,  7,  9, 10, 12, 14, 16,  18,
            20, 22, 25, 28, 31, 34, 37, 41, 45,  49,
            53, 57, 62, 67, 72, 77, 82, 88, 94, 100,
        };

        static bool buttonState;
        static int pwmIndex;
        static int pwmIncrement;
        static InterruptPort button;
        static PWM led;

        public static void Main()
        {
            pwmIndex = 0;
            pwmIncrement = 1;
            buttonState = false;

            // NOTE: You will need to connect an LED to Digital Pin 5 on the Netduino board.
            // Use a 100-ohm (brown-black-brown) resistor between the LED anode (+) and Digital Pin 5.
            // Connect the LED cathode (-) to one of the GND pins on the Power header.
            //
            // You can use any other PWM-enabled pin (5, 6, 9 or 10), but also remember to change
            // the Pin parameter in the PWM constructor below.

            led = new PWM(Pins.GPIO_PIN_D5);

            button = new InterruptPort(
                Pins.ONBOARD_SW1,
                false,
                Port.ResistorMode.Disabled,
                Port.InterruptMode.InterruptEdgeBoth);

            // Bind the interrupt handler to the pin's interrupt event.
            button.OnInterrupt += new NativeEventHandler(SwitchInterruptHandler);

            // Create a System.Threading.Timer instance and pass it the timer callback method.
            Timer pwmTimer = new Timer(
                new TimerCallback(PwmTimerCallback),
                null,
                pwmPeriod,
                pwmPeriod);

            Thread.Sleep(Timeout.Infinite);
        }

        public static void PwmTimerCallback(Object obj)
        {
            // Only change the LED brightness when the button is pushed (true).
            if (true == buttonState)
            {
                // Set the pin's new duty cycle.
                led.SetDutyCycle(gammaTable[pwmIndex]);
                pwmIndex += pwmIncrement;

                Debug.Print(gammaTable[pwmIndex].ToString());

                if (((gammaTable.Length - 1) == pwmIndex) || (0 == pwmIndex))
                {
                    // The duty cycle has hit the min or max value.
                    // Start ramping in the other direction.
                    pwmIncrement = -pwmIncrement;
                }
            }
        }

        public static void SwitchInterruptHandler(UInt32 data1, UInt32 data2, DateTime time)
        {
            button.DisableInterrupt();

            buttonState = (0 == data2);

            button.EnableInterrupt();
        }

    }
}

Thanks,
~ David ~

#2 djcult

djcult

    New Member

  • Members
  • Pip
  • 3 posts

Posted 18 August 2010 - 11:59 AM

I acheived something similar by using an "easing function" (which I stole some from WPF). You can set an acceleration and/or deceleration ratio. I have an acceleration ratio of 100% which means it starts off slowly and then speeds up; thus the LED appears to fade in linearly.

Code is here if you're interested.

private const int AccelerationRatio = 1; // Start off slowly and speed up
private const int DecelerationRatio = 0;

private void EasingFade(FadeMode fadeMode, int periodInMilliseconds)
        {
            var fadeIn = fadeMode == FadeMode.FadeIn;

            float progressRatio = fadeIn ? 0 : 1;

            while (fadeIn ? progressRatio <= 1 : progressRatio >= 0)
            {
                _pwnPort.SetDutyCycle(ComputeEasedProgressRatio(AccelerationRatio, DecelerationRatio, progressRatio));
                progressRatio = fadeIn ? progressRatio+0.01f : progressRatio-0.01f; // Increment or decrement by 1%

                Thread.Sleep(periodInMilliseconds / 100);
            }
        }

        private static float ComputeEasedProgressRatio(float accelerationRatio, float decelerationRatio, float progressRatio)
        {
            var combinedRatio = accelerationRatio + decelerationRatio;
            var num = progressRatio;
            if (combinedRatio == 0.0)
                return num;

            var num2 = (float)(2.0 / (2.0 - combinedRatio));
            if (num < accelerationRatio)
                return (float)(((num2 * num) * num) / (2.0 * accelerationRatio));

            if (num <= (1.0 - decelerationRatio))
                return (float)(num2 * (num - (accelerationRatio / 2.0)));

            var num5 = (float)(1.0 - num);
            return (float)(1.0 - (((num2 * num5) * num5) / (2.0 * decelerationRatio)));
        }


#3 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 18 August 2010 - 02:50 PM

Nice! I'm glad I brought a Netduino with me on vacation so I can play with this :)

#4 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 18 August 2010 - 03:17 PM

Nice! I'm glad I brought a Netduino with me on vacation so I can play with this :)


omg lol. you really do love this thing, just make sure you arent outside with those blinking lights in NY :(

#5 dab

dab

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationBellevue, WA, USA

Posted 18 August 2010 - 09:49 PM

Nice! I'm glad I brought a Netduino with me on vacation so I can play with this :)

You mean you actually take vacation? :P
Thanks,
~ David ~




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.