Skip to content

File syn_soft_pwm.c

File List > output > syn_soft_pwm.c

Go to the documentation of this file

#if __has_include("syn_config.h")
#include "syn_config.h"
#endif

#if !defined(SYN_USE_SOFT_PWM) || SYN_USE_SOFT_PWM

#include "../drivers/syn_gpio.h"
#include "../util/syn_assert.h"
#include "syn_soft_pwm.h"

#include <string.h>

void syn_soft_pwm_init(SYN_SoftPWM *pwm, SYN_GPIO_Pin pin, uint16_t resolution)
{
    SYN_ASSERT(pwm != NULL);
    SYN_ASSERT(resolution > 0);

    if (pwm == NULL || resolution == 0) {
        return;
    }

    memset(pwm, 0, sizeof(*pwm));
    pwm->pin = pin;
    pwm->resolution = resolution;
    pwm->duty = 0;
    pwm->counter = 0;
    pwm->active_high = true;

    syn_gpio_write(pin, SYN_GPIO_LOW);
}

void syn_soft_pwm_set_duty(SYN_SoftPWM *pwm, uint16_t duty)
{
    SYN_ASSERT(pwm != NULL);
    if (pwm == NULL) {
        return;
    }

    if (duty > pwm->resolution) {
        duty = pwm->resolution;
    }
    pwm->duty = duty;
}

void syn_soft_pwm_set_percent(SYN_SoftPWM *pwm, uint8_t percent)
{
    SYN_ASSERT(pwm != NULL);
    if (pwm == NULL) {
        return;
    }

    if (percent > 100)
        percent = 100;
    uint16_t duty = (uint16_t)(((uint32_t)percent * pwm->resolution + 50u) / 100u);
    pwm->duty = duty;
}

void syn_soft_pwm_tick(SYN_SoftPWM *pwm)
{
    SYN_ASSERT(pwm != NULL);
    if (pwm == NULL || pwm->resolution == 0) {
        return;
    }

    bool on;

    if (pwm->duty == 0) {
        on = false;
    } else if (pwm->duty >= pwm->resolution) {
        on = true;
    } else {
        on = (pwm->counter < pwm->duty);
    }

    SYN_GPIO_State level;
    if (pwm->active_high) {
        level = on ? SYN_GPIO_HIGH : SYN_GPIO_LOW;
    } else {
        level = on ? SYN_GPIO_LOW : SYN_GPIO_HIGH;
    }
    syn_gpio_write(pwm->pin, level);

    pwm->counter++;
    if (pwm->counter >= pwm->resolution) {
        pwm->counter = 0;
    }
}

void syn_soft_pwm_service(SYN_SoftPWM *channels, size_t count)
{
    SYN_ASSERT(channels != NULL || count == 0);
    if (channels == NULL || count == 0) {
        return;
    }

    for (size_t i = 0; i < count; i++) {
        syn_soft_pwm_tick(&channels[i]);
    }
}

#endif /* SYN_USE_SOFT_PWM */