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

There seems to be an algorithm problem with PWM usage.

Hello

I'd like to output two PWM alternately.  Using the timer, PWM1 and PWM2 alternate outputs every 5 seconds. And I want to change duty cycle according to adc value.

 

void PWM_SWAP(uint32_t period_us) 
{
    ret_code_t err_code;

    //disable PWM for PWM1,2 swap
    if(pwm_state == 1)
    {
      app_pwm_disable(&PWM1); //disable PWM 
      app_pwm_uninit(&PWM1); //uninitializing PWM
    }

    else if(pwm_state == 2) //if PWM2 running
    {
      app_pwm_disable(&PWM2);
      app_pwm_uninit(&PWM2); 
    } 

    if(pwm_state == 0 || pwm_state == 2) //first time or PWM2 running, PMW1 start
    {
      app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_1CH(period_us, 27);
    
      // Switch the polarity of the second channel. 
      pwm1_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;
    
      // Initialize and enable PWM. 
      err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback);
      APP_ERROR_CHECK(err_code);

      app_pwm_enable(&PWM1);
      pwm_state = 1;
    }

    else if(pwm_state == 1) //PWM1 running, PMW2 swap
    {
      app_pwm_config_t pwm2_cfg = APP_PWM_DEFAULT_CONFIG_1CH(period_us, 26);
    
      // Switch the polarity of the second channel. 
      pwm2_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;
    
      // Initialize and enable PWM. 
      err_code = app_pwm_init(&PWM2,&pwm2_cfg,pwm_ready_callback);
      APP_ERROR_CHECK(err_code);

      app_pwm_enable(&PWM2);
      pwm_state = 2;
    }
} 


//timer
static void PWM_swap_timer_handler(void * p_context) //1sec repeate time, toggle PWM1,2 for 5sec
{
  swap_timer_count++;

  printf("Timer count : %d\n", swap_timer_count);

  if(swap_timer_count == 5) //PWM swap every 5sec
  {
    //PWM_SWAP(adc_freq); 
    PWM_SWAP(2); //500kHz
    swap_timer_count = 0; //count clear
  }
}


static void timers_init(void)
{
    ret_code_t err_code;

    // Initialize timer module.
    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_create(&m_PWM_swap_timer_id,
                                APP_TIMER_MODE_REPEATED, 
                                PWM_swap_timer_handler);
    APP_ERROR_CHECK(err_code);
}


static void PWM_swap_timers_start()
{
    ret_code_t err_code;

    err_code = app_timer_start(m_PWM_swap_timer_id, APP_TIMER_TICKS(1000), NULL); //1sec repeate
    APP_ERROR_CHECK(err_code);
}


//saadc
void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}

#define ADC_TIME    100 //adc output time

void saadc_sampling_event_init(void) //SAADC example Reference
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    //timer setting
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32; //different scan mode example
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every ADC_TIME */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, ADC_TIME);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0, //timer channel
                                   ticks, //ADC_TIME
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, //Shortcut for clearing the timer based on compare 0.
                                   false);
    nrf_drv_timer_enable(&m_timer); 

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();


    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}


void saadc_callback(nrf_drv_saadc_evt_t const * p_event) 
{ 
   ret_code_t err_code;

   if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
   {
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);

        //NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
      
        for (int i = 0; i < SAMPLES_IN_BUFFER; i++) 
        {
            adc1 =  p_event->data.done.p_buffer[0];
            adc2 =  p_event->data.done.p_buffer[1];
            //NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
        }

        m_adc_evt_counter++;

        //adc 0~820
        if(adc1 < 0)
        {
          adc1 = 0;
        }

        else if(adc1 > 820)
        {
          adc1 = 820;
        }

        if(adc2 < 0)
        {
          adc2 = 0;
        }

        else if(adc2 > 820)
        {
          adc2 = 820;
        }

        printf("ADC1 : %d\n", adc1);
        printf("ADC2 : %d\n", adc2);

        //duty cycle 0~100%
        adc_duty1 = (adc1 - 0) * (100 - 0) / (820 - 0) + 0; 
        adc_duty2 = (adc2 - 0) * (100 - 0) / (820 - 0) + 0;
        
        now_freq = adc_freq; //Check if the frequency value has changed

        //printf("ADC_freq : %d\n", adc_freq);
        printf("Duty1 : %d\n", adc_duty1);
        printf("Duty2 : %d\n", adc_duty2);
   }
}


void saadc_init(void)
{
    ret_code_t err_code;
	
    //2 channel
    nrf_saadc_channel_config_t channel0_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1); //p0.003
   
    nrf_saadc_channel_config_t channel1_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); //p0.004


    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);


    err_code = nrf_drv_saadc_channel_init(0, &channel0_config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(1, &channel1_config);
    APP_ERROR_CHECK(err_code);


    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);
}

static void adc_configure(void)
{
    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();
}


int main(void)
{
    timers_init();
    adc_configure();

    PWM_swap_timers_start();

    // Enter main loop.
    for (;;)
    {
      if(pwm_state == 1)
      {
        APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 0, adc_duty1));
      }

      else if(pwm_state == 2)
      {
        APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM2, 0, adc_duty2));
      }
    } 
} 

When using this code, two PWMs are outputted well for the first few seconds, but after a short period of time, an error occurs in the 'app_pwm_channel_duty_set'

Maybe this is an algorithmic problem, can I get some help with this?

Thank you.

  • Hello,

    When using this code, two PWMs are outputted well for the first few seconds, but after a short period of time, an error occurs in the 'app_pwm_channel_duty_set'

    Which error is app_pwm_channel_duty_set returning?
    Please ensure that you have defined DEBUG in your preprocessor defines, like shown in the included image.
      
    Defining DEBUG will make a detailed error message be printed by your logger when a non-NRF_SUCCESS error code is passed to an APP_ERROR_CHECK. Please let me know what this error message reads.

    Best regards,
    Karl

Related