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

Unable to generate PWM pulse

Hi, I am trying to generate PWM pulse based on sample application in GitHub. However instead of using different modes and multiple channels, I tried to simplify it to just configuring Timer2, one channel, and one output pin. I am trying to set the duty cycle value in BLE data handler, using 2 PPI channels to toggle a pin once when it reaches CC[0] (to set the duty cycle) and once to finish a complete period CC[1]. I'm not getting any pulse on my oscilloscope. Attached PWM part of the code below, any hint on what might be wrong? Could there be any dependencies with other peripherals initialization?

// PWM Timer Definitions
#define PWM_TIMER			NRF_TIMER2
#define PWM_IRQHandler		TIMER2_IRQHandler
#define PWM_IRQn			TIMER2_IRQn
#define GPIOTE_CHANNEL_NO	2
#define PWM_MAX_VALUE		1000UL      // 1 tick equals 1µ , multiply by 1000 for ms value
uint16_t pwm_value;
uint8_t pwm_running;

/**@brief Function for Starting PWM timer.
 */
static void pwm_init(void)
{
	nrf_gpio_cfg_output(REGULATOR_PIN);		// Set regulator pin as output
	// Configure GPIOTE_CHANNEL_NUMBER to toggle the GPIO pin state with input.
	// nrf_gpiote_task_configure(GPIOTE_CHANNEL_NO, REGULATOR_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);                
	pwm_running = 0;

	// Configure TIMER2 for compare[0] event every 1 ms.
	PWM_TIMER->PRESCALER = 3;            // Prescaler 4 results in 1 tick equals 1 microsecond.
	PWM_TIMER->TASKS_CLEAR = 1;
	PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;	// 16 bit mode.
	PWM_TIMER->CC[1]     = PWM_MAX_VALUE;       // 1 tick equals 1µ , multiply by 1000 for ms value
	pwm_value = 300;
	PWM_TIMER->CC[0] = pwm_value;
	PWM_TIMER->MODE = TIMER_MODE_MODE_Timer;	// Set the timer in Timer Mode.
	PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk;
	PWM_TIMER->EVENTS_COMPARE[0] = PWM_TIMER->EVENTS_COMPARE[1] = 0;
	
	// Configure PPI channel 0 to toggle REGULATOR_PIN on every TIMER2 COMPARE[0] match
	sd_ppi_channel_assign(0, &(PWM_TIMER->EVENTS_COMPARE[0]), &(NRF_GPIOTE->TASKS_OUT[GPIOTE_CHANNEL_NO]));
	// Enable PPI channel 0
	sd_ppi_channel_enable_set(1 << 0);
	// Configure PPI channel 1 to toggle REGULATOR_PIN on every TIMER2 COMPARE[1] match
	sd_ppi_channel_assign(1, &(PWM_TIMER->EVENTS_COMPARE[1]), &(NRF_GPIOTE->TASKS_OUT[GPIOTE_CHANNEL_NO]));
	// Enable PPI channel 1
	sd_ppi_channel_enable_set(1 << 1);

	sd_nvic_SetPriority(PWM_IRQn, 1);	//must have to set the priority
//	sd_nvic_ClearPendingIRQ(PWM_IRQn);
	sd_nvic_EnableIRQ(PWM_IRQn);
  __enable_irq();
	
	/* Start clock */
	PWM_TIMER->TASKS_START = 1;
}

/**@brief   Sets the value for PWM
 *
 * @details Sets the variable for PWM value
 * In next interrupt the value is updated to the timer register
 * 
 */
static void pwm_set_value(uint16_t value)
{
	if(value <= PWM_MAX_VALUE)
	{
		pwm_value = value;
		PWM_TIMER->EVENTS_COMPARE[1] = 0;
		PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk;
		if((PWM_TIMER->INTENSET & TIMER_INTENSET_COMPARE1_Msk) == 0)
		{
			PWM_TIMER->TASKS_STOP = 1;
			PWM_TIMER->INTENSET = TIMER_INTENSET_COMPARE1_Msk;  
		}
		PWM_TIMER->TASKS_START = 1;
	}
}

/**@brief   Function for handling Timer2 interrupt.
 *
 * @details This function will set the PWM value to CC register
 * keeps the GPIO pin high/low at the max/min value of PWM respectively
 * 
 */
void PWM_IRQHandler(void)
{
	PWM_TIMER->EVENTS_COMPARE[1] = 0;
	PWM_TIMER->INTENCLR = 0xFFFFFFFF;

	if(pwm_value == 0)
	{
//		nrf_gpiote_unconfig(2);   Can anyone suggest what should be done here
//		nrf_gpiote_task_disable(0);
		nrf_gpio_pin_write(REGULATOR_PIN, 0);
		pwm_running = 0;
	}
	else if (pwm_value >= PWM_MAX_VALUE)
	{
//		nrf_gpiote_unconfig(2);   Can anyone suggest what should be done here
//		nrf_gpiote_task_disable(0);
		nrf_gpio_pin_write(REGULATOR_PIN, 1); 
		pwm_running = 0;
	}
	else
	{
		PWM_TIMER->CC[0] = pwm_value;
		if(pwm_running == 0)
		{
			// Configure GPIOTE_CHANNEL_NUMBER to toggle the GPIO pin state with input.
			nrf_gpiote_task_configure(GPIOTE_CHANNEL_NO, REGULATOR_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);                
			pwm_running = 1;
		}
	}

	PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk;
	PWM_TIMER->TASKS_START = 1;
}


/**@brief Application main function.
 */
int main(void)
{
    uint32_t err_code;
    bool erase_bonds;
    uint8_t  start_string[] = START_STRING;
    
    //  Initialize.
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);
    uart_init();
    buttons_leds_init(&erase_bonds);
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    pwm_init();
    
    printf("%s",start_string);

    err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);
    
    // Enter main loop.
    for (;;)
    {
      power_manage();
    }
}
Parents
  • Hi Ayan

    May I ask why you want to make your own pwm implementation? The basics of the pwm_library on Github is basically the same as you are proposing, i.e. a Timer using two CC registers, two PPIs and a single GPIOTE channel in Toggle mode. You can configure it for many PWM channels or just one PWM channel. You could configure it to a single PWM channel by defining your main function as e.g. :

    int main(void)
    {
    	nrf_pwm_config_t pwm_config = PWM_DEFAULT_CONFIG;
    	pwm_config.mode             = PWM_MODE_LED_255;
    	pwm_config.num_channels     = 1;
    	pwm_config.gpio_num[0]      = LED_1;
    
        nrf_pwm_init(&pwm_config);
    
    	nrf_pwm_set_value(0, 150);
    	nrf_delay_us(1000000);
    	nrf_pwm_set_value(0, 180);
    	nrf_delay_us(1000000);
    	nrf_pwm_set_value(0, 210);
    	nrf_delay_us(1000000);
    	nrf_pwm_set_value(0, 240);
    
        while(true){}
    }
    

    where the duty cycle of the configured channel is set 4 times.

    I recommend to use the pwm_library as it uses Timeslot API to safely update the pwm duty cycle, which is discussed on this thread a little.

  • Hi Ayan

    I have included an answer on this thread which hopefully answers your question.

Reply Children
No Data
Related