Skip to content

File PWM_Output.cpp

File List > examples > PWM_Output > PWM_Output.cpp

Go to the documentation of this file

Source Code

// Hardware PWM demo
//
// Demonstrates how to use a PWMHandle to output hardware-generated PWM.
// No special setup is required, as the built-in LED on the Seed is used for display.
//
#include "daisy_seed.h"
#include <cmath>

using namespace daisy;
using namespace daisy::seed;

DaisySeed hw;

const float TWO_PI = 6.2831853072f;

int main(void)
{
    // Initialize the Daisy Seed hardware
    hw.Init();
    hw.StartLog(false);

    // First, we'll create a PWMHandle that enables PWM mode on a given timer. Each handle provides up to 4 output channels.
    PWMHandle pwm_tim3;

    {
        // Configure the PWM peripheral
        PWMHandle::Config pwm_config;
        // We'll use TIM3 for PWM output.
        pwm_config.periph = PWMHandle::Config::Peripheral::TIM_3;
        // TIM3 is a 16-bit timer, so the max period is 0xffff. We'll use 0xff to give a higher-frequency PWM signal at the expense of lower precision.
        pwm_config.period = 0xff;

        // Initialize
        if(pwm_tim3.Init(pwm_config) != PWMHandle::Result::OK)
        {
            hw.PrintLine("Could not initialize PWM handle");
        }

        // You can also create the config inline when initializing:
        // pwm_tim3.Init({PWMHandle::Config::Peripheral::TIM_3});
    }

    {
        // Next, configure an individual channel. We'll use Channel 2, which can connect to the Seed's internal LED
        PWMHandle::Channel::Config channel_config;
        // Each timer and channel supports a different set of pins. If no pin is selected, the default for that channel will be selected.
        channel_config.pin = {PORTC, 7};
        // Polarity can be changed for individual channels
        channel_config.polarity = PWMHandle::Channel::Config::Polarity::HIGH;

        // Initialize
        if(pwm_tim3.Channel2().Init(channel_config) != PWMHandle::Result::OK)
        {
            hw.PrintLine("Could not initialize PWM channel");
        }

        // Like before, you can also create the config inline, or leave it blank to use defaults.
        // pwm_tim3.Channel2().Init();

        // Each PWMHandle supports up to 4 channels at once.
    }

    // Instead of calling pwm_tim3.Channel2() every time, you can also store a reference. Note that this reference is valid even if taken before initialization,
    // but it must be initialized after the PWMHandle and before calling Set().
    auto& led_pwm = pwm_tim3.Channel2();

    float phase = 0.0f;
    while(1)
    {
        // Generate a 1 Hz pulse
        float brightness = std::cos(TWO_PI * phase) * 0.5f + 0.5f;

        // Set the PWM channel duty cycle. We also apply a cubic gamma correction factor here to linearize the LED's brightness
        // When calling this method with a float, the value is normalized to [0, period]
        led_pwm.Set(brightness * brightness * brightness);

        // You can also call SetRaw to directly set the duty cycle.
        // led_pwm.SetRaw(0x7f);

        phase += 0.01f;
        if(phase > 1.0f)
            phase -= 1.0f;

        hw.DelayMs(10);
    }
}