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

nRF52832 PWM sequence endlessly by easyDMA

Hi, I'm developping endless PWM sequence.

That is ... Only one output pin and the signal from it is repeated with the same period of pulse but with two different duty setting contiguous and repeats back again.

3 cycles of Duty-A followed by 259 cycles of Duty-B and these total 262 cycles repeates forever. I would like to run PWM by itself to do that without any ISR support by CPU.

The scenario I suppose now is ... I need to set shortcuts that makes repeating behavior. At first, the same duty-A is applied for contiguous 3 PWM cycles. So, I can employ REFRESH=2 or ENDDELAY=2 setting to have following 2 cycle with the same duty that the first one does. Then, I need another duty-B. So, I need to employ the second sequence with REFRESH=258 or ENDDELAY=258 respectively as the first sequence. Then finally, for repeating those ones automatically, I need to set shortcut that invokes alternative sequence when the current sequence is done. Maybe a shortcut setting LOOPSDONE_SEQSTART0 would work fine initiated by TASKS_SEQSTART[0]. Regarding LOOP.CNT, a minimum non-ZERO value "1" would be enough.

Here, I have several questions in the scenario above: Q1: Which is better/reasonable employing REFRESH or ENDDELAY to get required numbers of repeating PWM with unchanged duty ? Q2: About DECODER.LOAD and SEQ[].CNT setting... I need only one output, so I need only one comarator. I do not want to allocate too much SRAM holding comparison value(s). Which .LOAD parameter is the proper one ? For only one comparator update, how much value should be set for .CNT ? Is that in-byte or in-number-of-halfwords ?

Or, am I completely misunderstanding and nRF52's easyDMA-ed PWM ?

Any comments or suggestions from NRF52 PWM experts ?

Regards, Shoichi Kojima

Parents
  • Hi,

    Have you considered using the PWM driver in the SDK?

    Here is some code that will give you 3 cycles of DUTY A, and 259 cycles of DUTY B, and will loop forever. This is with EasyDMA, and with no CPU usage.

    Code snippet:

    #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 "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    
    #define OUTPUT_PIN 4
    
    #define DUTY_A 50
    #define DUTY_B 80
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    
    static nrf_pwm_values_common_t /*const*/ seq0_values[] =
    {
             DUTY_A,DUTY_A,DUTY_A
    };
    
    nrf_pwm_sequence_t const seq0 =
    {
        .values.p_common = seq0_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq0_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    
    static nrf_pwm_values_common_t /*const*/ seq1_values[] =
    {
             DUTY_B,DUTY_B,DUTY_B,DUTY_B,DUTY_B,DUTY_B,DUTY_B
    };
    
    nrf_pwm_sequence_t const seq1 =
    {
        .values.p_common = seq1_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq1_values),
        .repeats         = 36,
        .end_delay       = 0
    };
    
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 100,
            .load_mode    = NRF_PWM_LOAD_COMMON,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        
    }
    
    
    int main(void)
    {
    
        // Start clock for accurate frequencies
        NRF_CLOCK->TASKS_HFCLKSTART = 1; 
        // Wait for clock to start   
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);   
        
        pwm_init();
    
       APP_ERROR_CHECK(nrf_drv_pwm_complex_playback(&m_pwm0, &seq0, &seq1, 1,
                                           NRF_DRV_PWM_FLAG_LOOP ));
    
        while(true)
        {
        __WFE();
        __SEV();
        __WFE();
    
        }
    }
    
    
    /** @} */
    
Reply
  • Hi,

    Have you considered using the PWM driver in the SDK?

    Here is some code that will give you 3 cycles of DUTY A, and 259 cycles of DUTY B, and will loop forever. This is with EasyDMA, and with no CPU usage.

    Code snippet:

    #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 "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    
    #define OUTPUT_PIN 4
    
    #define DUTY_A 50
    #define DUTY_B 80
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    
    static nrf_pwm_values_common_t /*const*/ seq0_values[] =
    {
             DUTY_A,DUTY_A,DUTY_A
    };
    
    nrf_pwm_sequence_t const seq0 =
    {
        .values.p_common = seq0_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq0_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    
    static nrf_pwm_values_common_t /*const*/ seq1_values[] =
    {
             DUTY_B,DUTY_B,DUTY_B,DUTY_B,DUTY_B,DUTY_B,DUTY_B
    };
    
    nrf_pwm_sequence_t const seq1 =
    {
        .values.p_common = seq1_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq1_values),
        .repeats         = 36,
        .end_delay       = 0
    };
    
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 100,
            .load_mode    = NRF_PWM_LOAD_COMMON,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        
    }
    
    
    int main(void)
    {
    
        // Start clock for accurate frequencies
        NRF_CLOCK->TASKS_HFCLKSTART = 1; 
        // Wait for clock to start   
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);   
        
        pwm_init();
    
       APP_ERROR_CHECK(nrf_drv_pwm_complex_playback(&m_pwm0, &seq0, &seq1, 1,
                                           NRF_DRV_PWM_FLAG_LOOP ));
    
        while(true)
        {
        __WFE();
        __SEV();
        __WFE();
    
        }
    }
    
    
    /** @} */
    
Children
No Data
Related