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

Please give me advice on nrf pwm driver.

I want a waveform as below for motor control.
I am trying to create this using nrf pwm driver.

I set the pwm sequence as below and checked the output.
2nd duty repeat does not work.

I added an unused 3rd dummy duty (line 91).
It seems to be working well.

However, increasing the playback count to 2 introduces a delay between the outputs.

What should I do to get the waveform I want?
Give me advice .
Thanks.

Parents
  • I want a waveform as below for motor control.
    I am trying to create this using nrf pwm driver.


    I set the pwm sequence as below and checked the output.
    2nd duty repeat does not work.


    I added an unused 3rd dummy duty (line 91).
    It seems to be working well.


    However, increasing the playback count to 2 introduces a delay between the outputs.


    What should I do to get the waveform I want?
    Give me advice .
    Thanks.

  • Hi,

    Have you tried passing NRF_DRV_PWM_FLAG_LOOP to nrf_drv_pwm_simple_playback()? Could you also share your code?

    regards

    Jared

  • I want to change the output cycle to be variable.
    So we use playback_count, NRFX_PWM_FLAG_STOP.

    Is there a way to repeat as many times as I want using NRF_DRV_PWM_FLAG_LOOP?

  • What I want to do is avoid "For sequences with configured repeating of duty cycle values, this might result in less than the requested number of repeats of the last value." in the description of NRFX_PWM_FLAG_STOP.
    Why is this happening?
    Is there any way to avoid this by using a trick?

  • Hi there,

    Would you mind sharing a minimal example that can be flashed on a DK that highlights the issue? It would make it much easier for me to understand the issue if I could reproduce it at my side. 

    regards

    Jared 

  • #include <stdio.h>
    #include <string.h>
    #include "nrf_drv_pwm.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    #include "bsp.h"
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    #define PERIOD 1000
    
    #define DUTY		75
    #define HIGH		(PERIOD * (100 - DUTY) / 100)
    #define LOW			PERIOD
    
    static nrf_pwm_values_individual_t /*const*/ seq_values[] =
    {
    	{HIGH, LOW, LOW, LOW},
    	{LOW, HIGH, LOW, LOW},
    };
    nrf_pwm_sequence_t const seq =
    {
    	.values.p_individual = seq_values,
    	.length              = NRF_PWM_VALUES_LENGTH(seq_values),
    	.repeats             = 4
    	,
    	.end_delay           = 0
    };
    
    static void demo(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                24,
                25,
                NRFX_PWM_PIN_NOT_USED,
                NRFX_PWM_PIN_NOT_USED
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
    		.top_value    = 1000,
            .load_mode    = PWM_DECODER_LOAD_Individual,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    }
    
    
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        app_error_save_and_stop(id, pc, info);
    }
    
    int main(void)
    {
    
    	demo();
    	
        for (;;)
        {
    		(void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRFX_PWM_FLAG_STOP);
    
    		nrf_delay_ms(1000);
        }
    }



    Code and output waveform

  • Hi there,

    Although it's not well explained in the product specification, the PWM peripheral has a limitation in that it will stop the execution of a sequence too early. Some effort has been done to explain it in some part in this thread

    Nevertheless, the best way for your use case is to something like this:

    #include <stdio.h>
    #include <string.h>
    #include "nrf_drv_pwm.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    #include "bsp.h"
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    #define PERIOD 1000
    
    #define DUTY		75
    #define HIGH		(PERIOD * (100 - DUTY) / 100) //250
    #define LOW			PERIOD //1000 
    
    static nrf_pwm_values_individual_t /*const*/ seq_values[] =
    {
        
    	{HIGH, LOW, LOW, LOW},
    	{HIGH, LOW, LOW, LOW},
        {HIGH, LOW, LOW, LOW},
        {HIGH, LOW, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
    };
    nrf_pwm_sequence_t const seq =
    {
    	.values.p_individual = seq_values,
    	.length              = NRF_PWM_VALUES_LENGTH(seq_values),
    	.repeats             = 0
    	,
    	.end_delay           = 0
    };
    
    static void demo(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                3,
                4,
                NRFX_PWM_PIN_NOT_USED,
                NRFX_PWM_PIN_NOT_USED
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
    		.top_value    = 1000,
            .load_mode    = PWM_DECODER_LOAD_Individual,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    }
    
    
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        app_error_save_and_stop(id, pc, info);
    }
    
    int main(void)
    {
    
    	demo();
    	
        for (;;)
        {
    		(void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 4 , NRFX_PWM_FLAG_STOP);
    
    		nrf_delay_ms(1000);
        }
    }

    Note, I changed the pins so you should probably change them back ;)

    Instead of using the repeat, I hardcoded the sequence pattern and use the playback_count parameter to nrfx_pwm_simple_playback() to decide the number of times the pattern should be repeated. Here is a trace from the logic analyzer with playback_count set to 4:

    best regards
    Jared
Reply
  • Hi there,

    Although it's not well explained in the product specification, the PWM peripheral has a limitation in that it will stop the execution of a sequence too early. Some effort has been done to explain it in some part in this thread

    Nevertheless, the best way for your use case is to something like this:

    #include <stdio.h>
    #include <string.h>
    #include "nrf_drv_pwm.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    #include "bsp.h"
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    #define PERIOD 1000
    
    #define DUTY		75
    #define HIGH		(PERIOD * (100 - DUTY) / 100) //250
    #define LOW			PERIOD //1000 
    
    static nrf_pwm_values_individual_t /*const*/ seq_values[] =
    {
        
    	{HIGH, LOW, LOW, LOW},
    	{HIGH, LOW, LOW, LOW},
        {HIGH, LOW, LOW, LOW},
        {HIGH, LOW, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
        {LOW, HIGH, LOW, LOW},
    };
    nrf_pwm_sequence_t const seq =
    {
    	.values.p_individual = seq_values,
    	.length              = NRF_PWM_VALUES_LENGTH(seq_values),
    	.repeats             = 0
    	,
    	.end_delay           = 0
    };
    
    static void demo(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                3,
                4,
                NRFX_PWM_PIN_NOT_USED,
                NRFX_PWM_PIN_NOT_USED
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
    		.top_value    = 1000,
            .load_mode    = PWM_DECODER_LOAD_Individual,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    }
    
    
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        app_error_save_and_stop(id, pc, info);
    }
    
    int main(void)
    {
    
    	demo();
    	
        for (;;)
        {
    		(void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 4 , NRFX_PWM_FLAG_STOP);
    
    		nrf_delay_ms(1000);
        }
    }

    Note, I changed the pins so you should probably change them back ;)

    Instead of using the repeat, I hardcoded the sequence pattern and use the playback_count parameter to nrfx_pwm_simple_playback() to decide the number of times the pattern should be repeated. Here is a trace from the logic analyzer with playback_count set to 4:

    best regards
    Jared
Children
Related