This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PWM Dutychange with a custom variable array

Hi , i am using the nRF52DK and i have a small problem with the pwm driver.

i basically would like that the frequency increases if i press a button or decreases if I press another button while keeping the same 50% duty cycle.

The way i attempted it is that i have an array with different top values that correspond to different frequencies. but I'm struggling to put it in seq_vallues and get the 50%. my code can be seen below.

thanks for your help 

#include <stdio.h>
#include <string.h>

#include "nrf_drv_pwm.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "boards.h"
#include "bsp.h"
#include "app_timer.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_gpiote.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
static nrf_drv_pwm_t m_pwm1 = NRF_DRV_PWM_INSTANCE(1);
static nrf_drv_pwm_t m_pwm2 = NRF_DRV_PWM_INSTANCE(2);

// This is for tracking PWM instances being used, so we can unintialize only
// the relevant ones when switching from one demo to another.
#define USED_PWM(idx) (1UL << idx)

#define LED2 NRF_GPIO_PIN_MAP(0,18)
#define BTN1 NRF_GPIO_PIN_MAP(0,13)
#define BTN2 NRF_GPIO_PIN_MAP(0,14)


static uint8_t m_used = 0;

 uint16_t               topvalue_array[12] = {16000,1600,8000,525,400,320,268,228,200,178,160,145};
 uint16_t               PWM_Counter;
static uint16_t const              m_demo1_top  = 400;
static uint16_t const              m_demo1_step = 25;
static uint8_t                     m_demo1_phase;
static nrf_pwm_values_individual_t m_demo1_seq_values;

void button_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action){
    if(action == NRF_GPIOTE_POLARITY_TOGGLE  && pin == BTN2){
        nrf_gpio_pin_toggle(LED2);
        PWM_Counter++;
    }
}


static nrf_pwm_sequence_t const    m_demo1_seq =
{
    .values.p_individual = &m_demo1_seq_values,
    .length              = NRF_PWM_VALUES_LENGTH(m_demo1_seq_values),
    .repeats             = 0,
    .end_delay           = 0
};

static void PWM_init(void)
{

    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            BSP_LED_0 | NRF_DRV_PWM_PIN_INVERTED, // channel 0
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_16MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = topvalue_array[0],
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_AUTO
    };

    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    m_used |= USED_PWM(0);

    static uint16_t  seq_values[] =
    {
        topvalue_array[0]/2 
    };

    nrf_pwm_sequence_t const seq =
    {
        .values.p_common = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };

    (void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
}

static void GPIOTE_init(void)
{

 // Configure LED GPIO
    nrf_gpio_cfg_output(LED2);
    nrf_gpio_pin_set(LED2);
    
    //Initialize GPIOTE driver
    nrf_drv_gpiote_init();
    
    //Configure button with pullup and event on both high and low transition
    nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
    config.pull = NRF_GPIO_PIN_PULLUP;

    nrf_drv_gpiote_in_init(BTN2, &config, button_event_handler); //Assign button config to a GPIOTE channel and assigning the interrupt handler

    nrf_drv_gpiote_in_event_enable(BTN2, true);                  //Enable event and interrupt
}

int main(void)
{

    
    PWM_Counter = topvalue_array[0];
    PWM_init();
    GPIOTE_init();

    
    for (;;)
    {
        // Wait for an event.
        __WFE();

        // Clear the event register.
        __SEV();
        __WFE();

       
    }
}

Parents
  • Hello,

    i am using the nRF52DK and i have a small problem with the pwm driver.

    i basically would like that the frequency increases if i press a button or decreases if I press another button while keeping the same 50% duty cycle.

    The way i attempted it is that i have an array with different top values that correspond to different frequencies. but I'm struggling to put it in seq_vallues and get the 50%. my code can be seen below.

    Unfortunately, the only way to change the pwm frequency is by disabling + uninitializing the pwm instance, before configuring the new frequency, init'ing and enabling it again.
    However, this is done pretty fast - much faster than the time it takes for you to finish pressing a button - so this should not be an issue for this application.
    There are multiple threads on the forums discussing this already. Please take a look at this thread, for a more in-depth discussion on the issue

    Best regards,
    Karl

Reply
  • Hello,

    i am using the nRF52DK and i have a small problem with the pwm driver.

    i basically would like that the frequency increases if i press a button or decreases if I press another button while keeping the same 50% duty cycle.

    The way i attempted it is that i have an array with different top values that correspond to different frequencies. but I'm struggling to put it in seq_vallues and get the 50%. my code can be seen below.

    Unfortunately, the only way to change the pwm frequency is by disabling + uninitializing the pwm instance, before configuring the new frequency, init'ing and enabling it again.
    However, this is done pretty fast - much faster than the time it takes for you to finish pressing a button - so this should not be an issue for this application.
    There are multiple threads on the forums discussing this already. Please take a look at this thread, for a more in-depth discussion on the issue

    Best regards,
    Karl

Children
  • Without writing an example, I think I would disagree, if I may. This would be the trick:

    // Structure holding duty cycle 0, 1 and 2 and top value which is max pwm pulse width
    // The 15-bit wave counter is responsible for generating the pulses at a duty cycle that depends on the compare
    // values, and at a frequency that depends on COUNTERTOP. MS bit is the sign, '1' active high starting pulse
    //
    //  DECODER.LOAD = Repeat
    //  =====================
    //  PWM with Nordic library code
    //
    //   +----------------------------------> COMP0 OUT[0] Compare 0 - PIN_PWM_1
    //   |         +------------------------> COMP1 OUT[1] Compare 1 - PIN_PWM_2
    //   |         |         +--------------> COMP2 OUT[2] Compare 2 - PIN_OTHER
    //   |         |         |               (COMP3 OUT[3] Compare 3 not used)
    //   |         |         |         
    // +---------+---------+---------+---------+
    // | Compare | Compare | Compare | Top     | Cycle N
    // +---------+---------+---------+---------+
    // | Compare | Compare | Compare | Top     | Cycle N+1
    // +---------+---------+---------+---------+
    //                                 |
    //                                 +----> COUNTERTOP Cycle Period 4 steps, 1MHz clocks. Range 3-32767

    The table is in RAM, and the PWM can be set up to LOOP or toggle between two tables. Since the data is in RAM and is read every PWM cycle it can be synchronously changed on-the-fly without stopping. The ratio Top:Compare=50%must be maintained of course.

Related