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

pwm_driver period is always 50Hz.WHY?

Hello all,

I have created a BLE application on nRF52 PCA10040 devboard with S132 SD, in which I would like to use a PWM with the PWM_Driver. My pwm source code as below wants to control an RGB LED on GPIO outputs:

#define TOPVALUE 1000	/* Value up to which the pulse generator counter counts */
static nrf_drv_pwm_t pwm 	= NRF_DRV_PWM_INSTANCE(1);
static nrf_pwm_values_individual_t seq_values_pwm;		/* Duty cycle values */
static nrf_pwm_sequence_t const seq_pwm =				/* Sequence of duty cycle values */
{
	.values.p_individual = &seq_values_pwm,
	.length				 = NRF_PWM_VALUES_LENGTH(seq_values_pwm),
	.repeats			 = 0,
	.end_delay			 = 0
};
void PWM_Init_f(void){

   ret_code_t err_code;

   nrf_drv_pwm_config_t const config_pwm =
   {
	   .output_pins =
	   {
		GPIO_O_PWM_RGB_R | NRF_DRV_PWM_PIN_INVERTED,			/* Channel 0 - RED   */
		GPIO_O_PWM_RGB_G | NRF_DRV_PWM_PIN_INVERTED,			/* Channel 1 - GREEN */
		GPIO_O_PWM_RGB_B | NRF_DRV_PWM_PIN_INVERTED, 			/* Channel 2 - BLUE  */
		GPIO_O_PWM_W     | NRF_DRV_PWM_PIN_INVERTED				/* Channel 3 - WHITE */
	   },
	   .irq_priority = APP_IRQ_PRIORITY_LOW,
       .base_clock   = NRF_PWM_CLK_1MHz,		/* Base Clock */
       .count_mode   = NRF_PWM_MODE_UP,
       .top_value    = TOPVALUE,
       .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
       .step_mode    = NRF_PWM_STEP_AUTO
   };
   err_code = nrf_drv_pwm_init(&pwm, &config_pwm, NULL);
   APP_ERROR_CHECK(err_code);
   }
void PWM_Update_f(int16_t dutyR, int16_t dutyG, int16_t dutyB, int16_t dutyW)
{
   /* TOPVALUE - : because the LEDs are woring with negative logic */
   seq_values_pwm.channel_0 = TOPVALUE - dutyR;
   seq_values_pwm.channel_1 = TOPVALUE - dutyG;
   seq_values_pwm.channel_2 = TOPVALUE - dutyB;
   seq_values_pwm.channel_3 = TOPVALUE - dutyW;

   nrf_drv_pwm_simple_playback(&pwm, &seq_pwm, 1, NRF_DRV_PWM_FLAG_STOP);
}

And it is triggered in void main() while a button is pressed:

...
PWM_Init_f();
while (true)
{
	sd_app_evt_wait();

	if(nrf_gpio_pin_read(GPIO_I_BUTTON_4) == BUTTON_PRESSED)
	{
		PWM_Update_f(100, 200, 500, 1000);
	}
}

I detect the signals with an oscilloscope on GPIO output, and I always get 50 Hz (20 msec) periods between the edges. Do you know what I did wrong? I would like to have more than 120 Hz period between the edges because of dimming an RGB LED. How is it possible?

Thank you in advance!

Regards,

Daniel

  • Hi,

    There is nothing wrong with the PWM part of the code itself. The problem is how you are starting the PWM sequence. When the button is pressed, it will continuously start a new PWM sequence. Problem with this is that it may start in the middle of the previous sequence. I recommend start the PWM sequence on a button pressed event, and stop the PWM sequence on a button release event, with the function nrf_drv_pwm_stop(). Are you using the BSP module in your code?

  • Hello Sigurd, I changed my code as you suggested, but I still get 50 Hz periods at 1MHz base frequency and 1000 TOPVALUE. By the way before your idea it worked the same way: when I released BUTTON_4, the pwm stopped because of NRF_DRV_PWM_FLAG_STOP. My question is how I can change the periods? Because I tried several base frequencies and TOPVALUEs. When I set 125kHz with 10000 TOPVALUE, the period frequency changed to 10 Hz. I don't really understand this behaviour, but one thing is the most annoying: I cannot go above 50 Hz period, but it would be really necessary for controlling RGB LEDs. I tried the pwm_app also, with that I could use any period frequencies what I wanted. But I want to use the pwm_driver, because it has much more features. And answering to you question: no, I don't use the BSP module in my code.

  • Try NRF_DRV_PWM_FLAG_LOOP, you should then only call the nrf_drv_pwm_simple_playback() once on a button pressed event, and then call nrf_drv_pwm_stop() on button release event. Use the button handler library to set-up the button events.

Related