<commit_before>/*
 * Copyright (C) 2018 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser General
 * Public License v2.1. See the file LICENSE in the top level directory for more
 * details.
 */

/**
 * @ingroup     cpu_nrf51
 * @ingroup     drivers_periph_pwm
 * @{
 *
 * @file
 * @brief       Low-level PWM driver implementation
 *
 * @author      <NAME> <<EMAIL>>
 * @}
 */

#include <stdint.h>
#include <string.h>

#include "periph/gpio.h"
#include "periph/pwm.h"

#define ENABLE_DEBUG        (0)
#include "debug.h"

#define PWM_PS_MAX          (9U)
#define PWM_PPI_CHANNELS    ((1 << PWM_PPI_A) | (1 << PWM_PPI_B))
#ifndef PWM_PERCENT_VAL
    #define PWM_PERCENT_VAL (1U)
#endif

static const uint32_t divtable[10] = {
    (CLOCK_CORECLOCK >> 0),
    (CLOCK_CORECLOCK >> 1),
    (CLOCK_CORECLOCK >> 2),
    (CLOCK_CORECLOCK >> 3),
    (CLOCK_CORECLOCK >> 4),
    (CLOCK_CORECLOCK >> 5),
    (CLOCK_CORECLOCK >> 6),
    (CLOCK_CORECLOCK >> 7),
    (CLOCK_CORECLOCK >> 8),
    (CLOCK_CORECLOCK >> 9),
};

static uint32_t init_data[2];

uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
{
    assert(dev == 0 && ((mode == PWM_LEFT) || (mode == PWM_RIGHT)));

    /* reset and configure the timer */
    PWM_TIMER->POWER = 1;
    PWM_TIMER->TASKS_STOP = 1;
    PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_32Bit;
    PWM_TIMER->MODE = TIMER_MODE_MODE_Timer;
    PWM_TIMER->TASKS_CLEAR = 1;

    /* calculate and set prescaler */
    uint32_t timer_freq = freq * res;
    uint32_t lower = (timer_freq - (PWM_PERCENT_VAL * (timer_freq / 100)));
    uint32_t upper = (timer_freq + (PWM_PERCENT_VAL * (timer_freq / 100)));
    for (uint32_t ps = 0; ps <= (PWM_PS_MAX + 1); ps++) {
        if (ps == (PWM_PS_MAX + 1)) {
            DEBUG("[pwm] init error: resolution or frequency not supported\n");
            return 0;
        }
        if ((divtable[ps] < upper) && (divtable[ps] > lower)) {
            PWM_TIMER->PRESCALER = ps;
            timer_freq = divtable[ps];
            break;
        }
    }

    /* reset timer compare events */
    PWM_TIMER->EVENTS_COMPARE[0] = 0;
    PWM_TIMER->EVENTS_COMPARE[1] = 0;
    /* init timer compare values */
    PWM_TIMER->CC[0] = 1;
    PWM_TIMER->CC[1] = res;

    /* configure PPI Event (set compare values and pwm width) */
    if (mode == PWM_LEFT) {
        NRF_GPIOTE->CONFIG[PWM_GPIOTE_CH] = (GPIOTE_CONFIG_MODE_Task     |
                                             (PWM_PIN << 8)              |
                                             GPIOTE_CONFIG_POLARITY_Msk  |
                                             GPIOTE_CONFIG_OUTINIT_Msk);
    }
    else if (mode == PWM_RIGHT) {
        NRF_GPIOTE->CONFIG[PWM_GPIOTE_CH] = (GPIOTE_CONFIG_MODE_Task     |
                                             (PWM_PIN << 8)              |
                                             GPIOTE_CONFIG_POLARITY_Msk);
    }

    /* configure PPI Channels (connect compare-event and gpiote-task) */
    NRF_PPI->CH[PWM_PPI_A].EEP = (uint32_t)(&PWM_TIMER->EVENTS_COMPARE[0]);
    NRF_PPI->CH[PWM_PPI_B].EEP = (uint32_t)(&PWM_TIMER->EVENTS_COMPARE[1]);

    NRF_PPI->CH[PWM_PPI_A].TEP =
        (uint32_t)(&NRF_GPIOTE->TASKS_OUT[PWM_GPIOTE_CH]);
    NRF_PPI->CH[PWM_PPI_B].TEP =
        (uint32_t)(&NRF_GPIOTE->TASKS_OUT[PWM_GPIOTE_CH]);

    /* enable configured PPI Channels */
    NRF_PPI->CHENSET = PWM_PPI_CHANNELS;

    /* shortcut to reset Counter after CC[1] event */
    PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk;

    /* start pwm with value '0' */
    pwm_set(dev, 0, 0);

    DEBUG("Timer frequency is set to %ld\n", timer_freq);

    return (uint32_t)(timer_freq / res);
}

void pwm_set(pwm_t dev, uint8_t channel, uint16_t value)
{
    assert((dev == 0) && (channel == 0));

    /*
     * make sure duty cycle is set at the beggining of each period
     * ensure to stop the timer as soon as possible
     */<commit_msg>cpu/nrf51: fix formatting uint to PRIu32<commit_after>/*
 * Copyright (C) 2018 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser General
 * Public License v2.1. See the file LICENSE in the top level directory for more
 * details.
 */

/**
 * @ingroup     cpu_nrf51
 * @ingroup     drivers_periph_pwm
 * @{
 *
 * @file
 * @brief       Low-level PWM driver implementation
 *
 * @author      <NAME> <<EMAIL>>
 * @}
 */

#include <stdint.h>
#include <string.h>
#include <inttypes.h>

#include "periph/gpio.h"
#include "periph/pwm.h"

#define ENABLE_DEBUG        (0)
#include "debug.h"

#define PWM_PS_MAX          (9U)
#define PWM_PPI_CHANNELS    ((1 << PWM_PPI_A) | (1 << PWM_PPI_B))
#ifndef PWM_PERCENT_VAL
    #define PWM_PERCENT_VAL (1U)
#endif

static const uint32_t divtable[10] = {
    (CLOCK_CORECLOCK >> 0),
    (CLOCK_CORECLOCK >> 1),
    (CLOCK_CORECLOCK >> 2),
    (CLOCK_CORECLOCK >> 3),
    (CLOCK_CORECLOCK >> 4),
    (CLOCK_CORECLOCK >> 5),
    (CLOCK_CORECLOCK >> 6),
    (CLOCK_CORECLOCK >> 7),
    (CLOCK_CORECLOCK >> 8),
    (CLOCK_CORECLOCK >> 9),
};

static uint32_t init_data[2];

uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
{
    assert(dev == 0 && ((mode == PWM_LEFT) || (mode == PWM_RIGHT)));

    /* reset and configure the timer */
    PWM_TIMER->POWER = 1;
    PWM_TIMER->TASKS_STOP = 1;
    PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_32Bit;
    PWM_TIMER->MODE = TIMER_MODE_MODE_Timer;
    PWM_TIMER->TASKS_CLEAR = 1;

    /* calculate and set prescaler */
    uint32_t timer_freq = freq * res;
    uint32_t lower = (timer_freq - (PWM_PERCENT_VAL * (timer_freq / 100)));
    uint32_t upper = (timer_freq + (PWM_PERCENT_VAL * (timer_freq / 100)));
    for (uint32_t ps = 0; ps <= (PWM_PS_MAX + 1); ps++) {
        if (ps == (PWM_PS_MAX + 1)) {
            DEBUG("[pwm] init error: resolution or frequency not supported\n");
            return 0;
        }
        if ((divtable[ps] < upper) && (divtable[ps] > lower)) {
            PWM_TIMER->PRESCALER = ps;
            timer_freq = divtable[ps];
            break;
        }
    }

    /* reset timer compare events */
    PWM_TIMER->EVENTS_COMPARE[0] = 0;
    PWM_TIMER->EVENTS_COMPARE[1] = 0;
    /* init timer compare values */
    PWM_TIMER->CC[0] = 1;
    PWM_TIMER->CC[1] = res;

    /* configure PPI Event (set compare values and pwm width) */
    if (mode == PWM_LEFT) {
        NRF_GPIOTE->CONFIG[PWM_GPIOTE_CH] = (GPIOTE_CONFIG_MODE_Task     |
                                             (PWM_PIN << 8)              |
                                             GPIOTE_CONFIG_POLARITY_Msk  |
                                             GPIOTE_CONFIG_OUTINIT_Msk);
    }
    else if (mode == PWM_RIGHT) {
        NRF_GPIOTE->CONFIG[PWM_GPIOTE_CH] = (GPIOTE_CONFIG_MODE_Task     |
                                             (PWM_PIN << 8)              |
                                             GPIOTE_CONFIG_POLARITY_Msk);
    }

    /* configure PPI Channels (connect compare-event and gpiote-task) */
    NRF_PPI->CH[PWM_PPI_A].EEP = (uint32_t)(&PWM_TIMER->EVENTS_COMPARE[0]);
    NRF_PPI->CH[PWM_PPI_B].EEP = (uint32_t)(&PWM_TIMER->EVENTS_COMPARE[1]);

    NRF_PPI->CH[PWM_PPI_A].TEP =
        (uint32_t)(&NRF_GPIOTE->TASKS_OUT[PWM_GPIOTE_CH]);
    NRF_PPI->CH[PWM_PPI_B].TEP =
        (uint32_t)(&NRF_GPIOTE->TASKS_OUT[PWM_GPIOTE_CH]);

    /* enable configured PPI Channels */
    NRF_PPI->CHENSET = PWM_PPI_CHANNELS;

    /* shortcut to reset Counter after CC[1] event */
    PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk;

    /* start pwm with value '0' */
    pwm_set(dev, 0, 0);

    DEBUG("Timer frequency is set to %" PRIu32 "\n", timer_freq);

    return (uint32_t)(timer_freq / res);
}

void pwm_set(pwm_t dev, uint8_t channel, uint16_t value)
{
    assert((dev == 0) && (channel == 0));

    /*
     * make sure duty cycle is set at the beggining of each period
     * ensure to stop the timer as soon as possible
     */
{'fraction_non_alphanumeric': 0.12789968652037617, 'fraction_numerical': 0.023573667711598745, 'mean_word_length': 2.3739424703891707, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 100, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3062186', 'n_tokens_mistral': 3163, 'n_tokens_neox': 2946, 'n_words': 626}