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

PWM SEQ0 interrupt

I am trying to do a ramping PWM. I want to update PWM every 25ms by increasing the duty cycle by 10%. I tried to setup a timer, by calling app_start_timer() on repeat mod and then within the timer callback i use the update_duty_cycle() found in the pwm example. However, the timer never seems to trigger no matter what i do. I have other timers that operate fine, this is the only timer that doesn't seem to run.

I then tried to do it with SEQ1 interrupts, I am using a simple pwm. so i thought the SEQ1 would be trigger every cycle, turn off -> turn off -> SEQ1 end trigger -> SEQ0 -> SEQ1.... where SEQ0 and SEQ1 are the same in simple playback using MODE_INDIVIDUAL. It appears the event handler only gets called after i stop the PWM.

Is there something i am missing here as to why the a) timer is not working as expected or b) by the SQ1 interrupt is not trigger every cycle?

#define MOTOR_PWM_DUTY_CYCLE      90
#define PWM_TOP_VALUE             100
#define DUTY_CYCLE_RAMP_CHANGE_MS 25

APP_TIMER_DEF(pwm_duty_cycle_timer_id);

static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
static uint8_t pwm_duty_cycle;

static nrf_pwm_values_individual_t seq_values[] = {{MOTOR_PWM_DUTY_CYCLE, 0, 0, 0}};
static nrf_pwm_sequence_t const seq =
{
    .values.p_individual  = seq_values,
    .length               = NRF_PWM_VALUES_LENGTH(seq_values),
    .repeats              = 0,
    .end_delay            = 0
};


// Set duty cycle between 0 and 100%. This isinverse. Duty Cycls is OFF time
void pwm_update_duty_cycle(uint8_t duty_cycle)
{
    if(duty_cycle <= 0){
        seq_values->channel_0 = 0;
    }else{
        seq_values->channel_0 = duty_cycle;
    }
    nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP | NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1);
}

static void pwm_event_handler(nrf_drv_pwm_evt_type_t event_type)
{

    if (event_type == NRF_DRV_PWM_EVT_END_SEQ1){
        if(pwm_duty_cycle > 0){
            pwm_duty_cycle -= 10;
            //nrf_drv_pwm_stop(&m_pwm0, false);
            pwm_update_duty_cycle(pwm_duty_cycle);
        }
    }

}

static void pwm_duty_cycle_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);

    if(pwm_duty_cycle > 0){
        pwm_duty_cycle -= 10;
        nrf_drv_pwm_stop(&m_pwm0, false);
        pwm_update_duty_cycle(pwm_duty_cycle);
    }
}

static void init_timers(void){
    uint32_t err_code;
    
    err_code = app_timer_create(&pwm_duty_cycle_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                pwm_duty_cycle_timeout_handler);
    APP_ERROR_CHECK(err_code);
}

static void motor_drv_pwm_init(void)
{
    uint32_t err_code;

    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            IN1_PIN,                              // 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_1MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 100,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    
    init_timers();

    err_code = nrf_drv_pwm_init(&m_pwm0, &config0, pwm_event_handler);
    APP_ERROR_CHECK(err_code);
}

bool motor_drv_forward(void)
{
    bool result = false;
    uint32_t err_code;

    if(s_initialized)
    {
        nrf_gpio_pin_write(EN_PIN, PIN_ACTIVE);
        nrf_delay_ms(300);
        
        app_timer_start(pwm_duty_cycle_timer_id, APP_TIMER_TICKS(DUTY_CYCLE_RAMP_CHANGE_MS), NULL);
        pwm_duty_cycle = 90;
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP | NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1);
        result = true;
    }

    return result;
}

  • I was able to get a ramping using a complex pwm call. per below. but i am still curious to know the answers to my questions on why the timer and the pwm seq0 callback was not working

    uint16_t value = PWM_RAMP_TOP;
    uint8_t  i;
    for (i = 0; i < 10; i++){
    pwm_ramp_values[i] = value;
    value              -= PWM_RAMP_TOP / 10;
    }
    
    static nrf_pwm_sequence_t const ramp_seq0 =
    {
    .values.p_common      = pwm_ramp_values,
    .length               = NRF_PWM_VALUES_LENGTH(pwm_ramp_values),
    .repeats              = 200,
    .end_delay            = 0
    };
    
    static nrf_pwm_sequence_t const ramp_seq1 =
    {
    .values.p_common      = pwm_ramp_full_on,
    .length               = NRF_PWM_VALUES_LENGTH(pwm_ramp_full_on),
    .repeats              = 20000,
    .end_delay            = 0
    };
    nrf_drv_pwm_complex_playback(&m_pwm0, &ramp_seq0, &ramp_seq1, 1, NRF_DRV_PWM_FLAG_LOOP);

  • I was able to get a ramping using a complex pwm call.

    Good.

    but i am still curious to know the answers to my questions on why the timer and the pwm seq0 callback was not working

    I don't see any bugs in the code you posted, and I was not able to reproduce the issue. But it could be that s_initialized= false, so that app_timer_start() was never called. Another theory could be that the LFCLK was not running, if the SoftDevice is not running, the LFCLK must be requested explicitly. See the app timer tutorial chapter called "initialization".

Related