PWM sleep

Hi, I've noticed much higher than expected power usage and I've narrowed it down to PWM. I need to be able to turn off the PWMs when they're not needed.

I use all 4 PWMs (PWM0, PWM1, PWM2, PWM3)

I use this code to turn them off.

void nrf_pwm_stop()
{
   	NRF_PWM0->TASKS_STOP = 1 << PWM_TASKS_STOP_TASKS_STOP_Pos;
    NRF_PWM1->TASKS_STOP = 1 << PWM_TASKS_STOP_TASKS_STOP_Pos;
    NRF_PWM2->TASKS_STOP = 1 << PWM_TASKS_STOP_TASKS_STOP_Pos;
    NRF_PWM3->TASKS_STOP = 1 << PWM_TASKS_STOP_TASKS_STOP_Pos;

	do
    {

    } while (
        (!NRF_PWM0->EVENTS_STOPPED) ||
        (!NRF_PWM1->EVENTS_STOPPED) ||
        (!NRF_PWM2->EVENTS_STOPPED) ||
        (!NRF_PWM3->EVENTS_STOPPED));


    NRF_PWM0->PSEL.OUT[0]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM0->PSEL.OUT[1]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM0->PSEL.OUT[2]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM0->PSEL.OUT[3]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);

    NRF_PWM1->PSEL.OUT[0]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM1->PSEL.OUT[1]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM1->PSEL.OUT[2]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM1->PSEL.OUT[3]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
	NRF_PWM1->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);

    NRF_PWM2->PSEL.OUT[0]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM2->PSEL.OUT[1]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM2->PSEL.OUT[2]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM2->PSEL.OUT[3]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM2->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);

    NRF_PWM3->PSEL.OUT[0]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM3->PSEL.OUT[1]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM3->PSEL.OUT[2]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM3->PSEL.OUT[3]=(PWM_PSEL_OUT_CONNECT_Disconnected<<PWM_PSEL_OUT_CONNECT_Pos);
    NRF_PWM3->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);


}

Here is my test main loop

void main()
{
	int ret;

	if (!device_is_ready(button0.port))					return false;
	if (!device_is_ready(button1.port))					return false;
	if (!device_is_ready(button2.port))					return false;
	if (!device_is_ready(button3.port))					return false;

	ret = gpio_pin_configure_dt(&button0, GPIO_INPUT);
	ret = gpio_pin_configure_dt(&button1, GPIO_INPUT);
	ret = gpio_pin_configure_dt(&button2, GPIO_INPUT);
	ret = gpio_pin_configure_dt(&button3, GPIO_INPUT);

	do
	{
		k_msleep(10000);
		nrf_pwm_start();
		nrf_pwm_stop();

	} 
	while (true);

}

I've noticed an unexpected power draw 2 seconds after turning PWM off. My guess is that this is caused by the sequences ending because each takes 1 second.

Here is the power profiler output. As you can see I get 4uA current during k_msleep and then 2 seconds after nrf_pwm_stop() I see 3mA current draw. So it seems that my code to stop the PWM is wrong somehow.

Any help is greatly appreciated because I don't know what might be wrong with this.

  • Also, is there an electrical specification for PWM? I can't find one in the 52833 product spec. I'm not sure what current I should expect or how to reduce it. 

    I seem to see around 800uA of current just from enabling PWM, without even illuminating any leds (zero duty cycle). I anticipated it would be a few uA's so it would be nice to reduce this.

    I'm especially interested in reducing the current when only 1 pin is connected. Most of the time I just need it to dim a single LED. I don't need fine control of the brightness. 

    Thanks for your help, as always Slight smile

  • Ok, I am not sure what I changed, but this is now working as expected! Very strange.

    I changed my pwm_init to use 

        NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
        NRF_PWM1->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
        NRF_PWM2->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
        NRF_PWM3->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
    prior to setting up PWM0, PWM1, PWM2 and PWM3.
    and then after they're set up, I use this code to start them.
        NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
        NRF_PWM1->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
        NRF_PWM2->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
        NRF_PWM3->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
    
    
        NRF_PWM0->TASKS_SEQSTART[0] = PWM_TASKS_SEQSTART_TASKS_SEQSTART_Trigger << PWM_TASKS_SEQSTART_TASKS_SEQSTART_Pos;
        NRF_PWM1->TASKS_SEQSTART[0] = PWM_TASKS_SEQSTART_TASKS_SEQSTART_Trigger << PWM_TASKS_SEQSTART_TASKS_SEQSTART_Pos;
        NRF_PWM2->TASKS_SEQSTART[0] = PWM_TASKS_SEQSTART_TASKS_SEQSTART_Trigger << PWM_TASKS_SEQSTART_TASKS_SEQSTART_Pos;
        NRF_PWM3->TASKS_SEQSTART[0] = PWM_TASKS_SEQSTART_TASKS_SEQSTART_Trigger << PWM_TASKS_SEQSTART_TASKS_SEQSTART_Pos;
    
    I then use the code I posted earlier to stop them again, and I get back to 3uA sleep current. 
    I've had intermittent problems flashing boards in NCS, it appears to upload the new firmware, but then the changes aren't present.
    And if I run it with the debugger then it fixes it. I'm not sure why there would be a difference. Maybe a different flash procedure.
    I also find that if I use the debugger then sometimes later I can't reset my board. The only way to continue is to use the debugger, or use "recover board" to get it back.

    Maybe this happened earlier. I'm not sure.

    But anyway, RIGHT NOW, it's working Slight smile

    Glaedlig Jul!

  • If you can help me with this then that would be great, I've tested the power usage with only 1 PWM enabled and it's still the same 800uA figure. 

    Almost all the time I simply need to illuminate a single LED, dimmed to around 5% or 50%. I don't need a sequence, just a constant. Is there any way to use less power? 

    In the 50% case I considered trying to coerce the clock from the TWI or SPI peripherals to give me the 50% dimming, but that doesn't help me with the 5% case. 

    I read somewhere that the PWM uses less power if it uses the 125khz clock, but I can't see any way to change the base clock. 

  • Hi there,

    800 µA is the HFCLK that is started once the PWM peripheral is enabled which is as expected. Does the current decrease once you disable the peripheral? In the nRF5SDK we had a library that bit-banged PWM and used the RTC instead of the HFCLK to decrease the current consumption. We have yet to develop such a driver for the Zephyr RTOS, but you can find the low power pwm driver in nRF5SDK if you would like to try it yourself. Lastly, I totally agree that we should have an electrical section for the PWM peripheral just as we have for other peripherals.

    regards

    Jared 

  • Hi Jared, yes, current decreases if I turn off PWM, I get 3uA.

    But when my product runs it always shows at least one LED, so I cannot turn off the PWM.

    I've just found the low_power_pwm library! THANK YOU! 

    Merry Christmas Slight smile

Related