Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to set duty cycle of two pwm channel in opposite polarity inside gpio interrupt handler?

I am quite new with nordic environment .

My application is to start 2 pwm instance in opposite polarity (i.e 1 high polarity and another is low polarity with same duty cycle) when got interrupt in gpio pin.

I am able to create the same by using PWM_Library example in SDK .

Here is my code 

#define    Period    20000 //20ms
#define    PIN_IN    22
#define    PWM_PIN  (11UL)

int duty_1= 20;

static volatile bool ready_flag;            
static int gpio_flag =0;

APP_PWM_INSTANCE(PWM1,1);                   
APP_PWM_INSTANCE(PWM2,2);

void pwm_ready_callback(uint32_t pwm_id)    // PWM callback function
{
    ready_flag = true;
}

void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
   gpio_flag =1;
}

static void gpio_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    in_config.pull = NRF_GPIO_PIN_PULLDOWN;

    err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(PIN_IN, true);
}

static void pwm_pin_init(void)
{
 ret_code_t err_code;

    app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_1CH(Period, BSP_LED_0);
    app_pwm_config_t pwm2_cfg = APP_PWM_DEFAULT_CONFIG_1CH(Period, BSP_LED_1);

    
    pwm1_cfg.pin_polarity [0]= APP_PWM_POLARITY_ACTIVE_HIGH;
    pwm2_cfg.pin_polarity [0]= APP_PWM_POLARITY_ACTIVE_LOW;


    
    err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback);

    APP_ERROR_CHECK(err_code);

    err_code = app_pwm_init(&PWM2,&pwm2_cfg,pwm_ready_callback);

    APP_ERROR_CHECK(err_code);
    app_pwm_enable(&PWM1);
    app_pwm_enable(&PWM2);

} 

int main(void)
{
 bsp_board_init(BSP_INIT_LEDS);

    gpio_init();

    pwm_pin_init();

    uint32_t value;

  while(true)
  {

    if(gpio_flag == 1)
    {
      value = duty_1;
      gpio_flag =0;

      ready_flag = false;
      /* Set the duty cycle - keep trying until PWM is ready... */
      
      
      while ((app_pwm_channel_duty_set(&PWM1, 0, value))&(app_pwm_channel_duty_set(&PWM2, 0, value)) == NRF_ERROR_BUSY);
 
      /* ... or wait for callback. */
      while (!ready_flag);
      APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 0, value));
      APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM2, 0, value));
   
     // nrf_delay_ms(25);
    }

    else
    {
     app_pwm_channel_duty_set(&PWM1, 0, 0);
     app_pwm_channel_duty_set(&PWM2, 0, 0);
    }
  }
}

This code is working properly but I want to set duty cycle inside the interrupt function not in main function .

So how to do so because I tried but without any success.

So guide me .

Parents
  • Hi,

    I notice you are using app_pwm, which is not actually the PWM hardware peripheral instance, but instead app_pwm is using several ppi, gpiote and timer to create a PWM signal:
    https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.0.2/lib_pwm.html 

    You may get into trouble updating the PWM in such case since it will depend on the interrupt priority of those peripherals.

    I instead suggest that you use the PWM hardware peripheral, which have no such dependencies.

    You can find an example here that show how you can setup the PWM peripheral:
    https://devzone.nordicsemi.com/f/nordic-q-a/39314/pwm-update_function/152602#152602

    You can find an example below where pwm channel 1 is inverted of pwm channel 0:

    /cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-e7e4528908a64f45bf120ad5a23ef4b4/25464.main.c 

    The above main.c is a modification of \nRF5_SDK_17.0.2_d674dde\examples\peripheral\pwm_driver

  • Hello, Kenneth

    I tried using pwm hardware peripheral but It's not working can You please guide me where is the fault in my code??

    #define OUTPUT_PIN LED_1
    #define OUTPUT_PIN2 LED_2
    
    #define    PIN_IN    22
    #define    PWM_PIN   11
    
    
    unsigned int duty = 4000 ;
    static volatile bool  gpio_flag;
      
    
    static int16_t buf[] = {10000}; // Inverse polarity (bit 15), 10000us duty cycle
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
       gpio_flag = true;
    }
    
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
        in_config.pull = NRF_GPIO_PIN_PULLDOWN;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, true);
    }
    
    
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycle(uint16_t duty_cycle)
    {
        
       
        {
            seq_values->channel_0 = duty_cycle ;
            seq_values->channel_1 = duty_cycle | 0x8000;
        }
        
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                OUTPUT_PIN2,             // 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_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 10000,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        
    }
    
    static void zcd_init(void)
    {
    
     // Configure PWM_PIN as output, and set it to 0
      NRF_GPIO->DIRSET = (1 << PWM_PIN);
      NRF_GPIO->OUTCLR = (1 << PWM_PIN);
      
      
      NRF_PWM0->PRESCALER   = PWM_PRESCALER_PRESCALER_DIV_16; // 1 us
      NRF_PWM0->PSEL.OUT[0] = PWM_PIN;
      NRF_PWM0->MODE        = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
      NRF_PWM0->DECODER     = (PWM_DECODER_LOAD_Individual       << PWM_DECODER_LOAD_Pos) | 
                              (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
      NRF_PWM0->LOOP        = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
      
      NRF_PWM0->COUNTERTOP = 20000; // 20ms period
      
      
      NRF_PWM0->SEQ[0].CNT = ((sizeof(buf) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
      NRF_PWM0->SEQ[0].ENDDELAY = 0;
      NRF_PWM0->SEQ[0].PTR = (uint32_t)&buf[0];
      NRF_PWM0->SEQ[0].REFRESH = 0;
      NRF_PWM0->SHORTS = 0;
      
      NRF_PWM0->ENABLE = 1;
      NRF_PWM0->TASKS_SEQSTART[0] = 1;
    }
    
    int main(void)
    {
    
      // Start accurate HFCLK (XOSC)
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
       
        bsp_board_init(BSP_INIT_LEDS);
        zcd_init();
        gpio_init();
        pwm_init();
        gpio_flag = false;
        
    
        while (1)
        {
            //if (gpio_flag == true)
            {
              gpio_flag = false;
              unsigned int val = duty;
              pwm_update_duty_cycle(val);
            }
        }
    }
    

    Mainly my zcd_init() function is not working . where I created an 50% duty cycle signal of 20 ms period and given to my gpio interrupt pin 22.

Reply
  • Hello, Kenneth

    I tried using pwm hardware peripheral but It's not working can You please guide me where is the fault in my code??

    #define OUTPUT_PIN LED_1
    #define OUTPUT_PIN2 LED_2
    
    #define    PIN_IN    22
    #define    PWM_PIN   11
    
    
    unsigned int duty = 4000 ;
    static volatile bool  gpio_flag;
      
    
    static int16_t buf[] = {10000}; // Inverse polarity (bit 15), 10000us duty cycle
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
       gpio_flag = true;
    }
    
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
        in_config.pull = NRF_GPIO_PIN_PULLDOWN;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, true);
    }
    
    
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycle(uint16_t duty_cycle)
    {
        
       
        {
            seq_values->channel_0 = duty_cycle ;
            seq_values->channel_1 = duty_cycle | 0x8000;
        }
        
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                OUTPUT_PIN2,             // 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_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 10000,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        
    }
    
    static void zcd_init(void)
    {
    
     // Configure PWM_PIN as output, and set it to 0
      NRF_GPIO->DIRSET = (1 << PWM_PIN);
      NRF_GPIO->OUTCLR = (1 << PWM_PIN);
      
      
      NRF_PWM0->PRESCALER   = PWM_PRESCALER_PRESCALER_DIV_16; // 1 us
      NRF_PWM0->PSEL.OUT[0] = PWM_PIN;
      NRF_PWM0->MODE        = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
      NRF_PWM0->DECODER     = (PWM_DECODER_LOAD_Individual       << PWM_DECODER_LOAD_Pos) | 
                              (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
      NRF_PWM0->LOOP        = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
      
      NRF_PWM0->COUNTERTOP = 20000; // 20ms period
      
      
      NRF_PWM0->SEQ[0].CNT = ((sizeof(buf) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
      NRF_PWM0->SEQ[0].ENDDELAY = 0;
      NRF_PWM0->SEQ[0].PTR = (uint32_t)&buf[0];
      NRF_PWM0->SEQ[0].REFRESH = 0;
      NRF_PWM0->SHORTS = 0;
      
      NRF_PWM0->ENABLE = 1;
      NRF_PWM0->TASKS_SEQSTART[0] = 1;
    }
    
    int main(void)
    {
    
      // Start accurate HFCLK (XOSC)
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
       
        bsp_board_init(BSP_INIT_LEDS);
        zcd_init();
        gpio_init();
        pwm_init();
        gpio_flag = false;
        
    
        while (1)
        {
            //if (gpio_flag == true)
            {
              gpio_flag = false;
              unsigned int val = duty;
              pwm_update_duty_cycle(val);
            }
        }
    }
    

    Mainly my zcd_init() function is not working . where I created an 50% duty cycle signal of 20 ms period and given to my gpio interrupt pin 22.

Children
Related