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

Issues with PWM and GPIOTE: interrupt masking and missing pulses

Hi,

Problems I am having with PWM:

1. Using app_PWM and GPIOTE to start and stop the PWM: When button is pressed, GPIOTE handler sets a flag that is polled to start the PWM. PWM starts "app_pwm_enable(&PWM1);" and the GPIOTE does not responds to any other button presses. I tried to manioulate the IRQ priority for the GPIOTE but no good.

2. Using driver PWM or app_PWM to produce 4MHz pulses, starting with 8MHz or 16MHz clock, there are always missing pulses.

any advice ?

thanks

Parents
  • Hi,

    I recommend using PWM driver for this.

    Here is some example code on how to generate a defined number of 4 MHz pulses when a button on the DK is pressed.

    /**
     * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    /** @file
     * @defgroup pwm_example_main main.c
     * @{
     * @ingroup pwm_example
     *
     * @brief PWM Example Application main file.
     *
     * This file contains the source code for a sample application using PWM.
     */
    
    #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_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 PWM_PIN 3
    
    #define TOP_VALUE 4
    
    // Set to the number of pulses to be generated
    #define PULSES 12
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t config =
        {
            // These are the common configuration options we use for all PWM
            // instances.
            .irq_priority = APP_IRQ_PRIORITY_HIGH,
            .count_mode   = NRF_PWM_MODE_UP,
            .step_mode    = NRF_PWM_STEP_AUTO,
        };
    
        config.base_clock = NRF_PWM_CLK_16MHz;
        config.top_value  = TOP_VALUE;
        config.load_mode  = NRF_PWM_LOAD_COMMON;
    
        config.output_pins[0] = PWM_PIN;
        config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
        config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
        config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config, NULL));
    }
    
    static void generate_pulse_1mhz(uint16_t pulses)
    {
    
        static uint16_t /*const*/ seq_values[] ={0,0x8000};
        
        nrf_pwm_sequence_t const seq =
        {
            .values.p_common = seq_values,
            .length          = NRF_PWM_VALUES_LENGTH(seq_values),
            .repeats         = 0,
            .end_delay       = 0
        };
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, pulses,  NRF_DRV_PWM_FLAG_STOP);
    
    }
    static void bsp_evt_handler(bsp_event_t evt)
    {
        switch (evt)
        {
            
            case BSP_EVENT_KEY_0:
                 generate_pulse_1mhz(PULSES);
    
                 break;
    
           
           case BSP_EVENT_KEY_1:
    
                       break;
                
            default:
                return;
        }
    
    }
    
    
    
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        bsp_board_leds_on();
        app_error_save_and_stop(id, pc, info);
    }
    
    static void init_bsp()
    {
        APP_ERROR_CHECK(nrf_drv_clock_init());
        nrf_drv_clock_lfclk_request(NULL);
    
        APP_ERROR_CHECK(app_timer_init());
        APP_ERROR_CHECK(bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler));
        APP_ERROR_CHECK(bsp_buttons_enable());
    }
    
    
    int main(void)
    {
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
    
        NRF_LOG_INFO("PWM example started.");
        init_bsp();
    
        bool accurate_HFCLK = true;
    
        if(accurate_HFCLK)
        {
          // Start accurate HFCLK (XOSC), will consume more current!
          NRF_CLOCK->TASKS_HFCLKSTART = 1;
          while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
          NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        }
    
        pwm_init();
    
    
        for (;;)
        {
            // Wait for an event.
            __WFE();
    
            // Clear the event register.
            __SEV();
            __WFE();
    
            NRF_LOG_FLUSH();
        }
    }
    
    
    /** @} */
     

Reply
  • Hi,

    I recommend using PWM driver for this.

    Here is some example code on how to generate a defined number of 4 MHz pulses when a button on the DK is pressed.

    /**
     * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    /** @file
     * @defgroup pwm_example_main main.c
     * @{
     * @ingroup pwm_example
     *
     * @brief PWM Example Application main file.
     *
     * This file contains the source code for a sample application using PWM.
     */
    
    #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_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 PWM_PIN 3
    
    #define TOP_VALUE 4
    
    // Set to the number of pulses to be generated
    #define PULSES 12
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t config =
        {
            // These are the common configuration options we use for all PWM
            // instances.
            .irq_priority = APP_IRQ_PRIORITY_HIGH,
            .count_mode   = NRF_PWM_MODE_UP,
            .step_mode    = NRF_PWM_STEP_AUTO,
        };
    
        config.base_clock = NRF_PWM_CLK_16MHz;
        config.top_value  = TOP_VALUE;
        config.load_mode  = NRF_PWM_LOAD_COMMON;
    
        config.output_pins[0] = PWM_PIN;
        config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
        config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
        config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config, NULL));
    }
    
    static void generate_pulse_1mhz(uint16_t pulses)
    {
    
        static uint16_t /*const*/ seq_values[] ={0,0x8000};
        
        nrf_pwm_sequence_t const seq =
        {
            .values.p_common = seq_values,
            .length          = NRF_PWM_VALUES_LENGTH(seq_values),
            .repeats         = 0,
            .end_delay       = 0
        };
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, pulses,  NRF_DRV_PWM_FLAG_STOP);
    
    }
    static void bsp_evt_handler(bsp_event_t evt)
    {
        switch (evt)
        {
            
            case BSP_EVENT_KEY_0:
                 generate_pulse_1mhz(PULSES);
    
                 break;
    
           
           case BSP_EVENT_KEY_1:
    
                       break;
                
            default:
                return;
        }
    
    }
    
    
    
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        bsp_board_leds_on();
        app_error_save_and_stop(id, pc, info);
    }
    
    static void init_bsp()
    {
        APP_ERROR_CHECK(nrf_drv_clock_init());
        nrf_drv_clock_lfclk_request(NULL);
    
        APP_ERROR_CHECK(app_timer_init());
        APP_ERROR_CHECK(bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler));
        APP_ERROR_CHECK(bsp_buttons_enable());
    }
    
    
    int main(void)
    {
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
    
        NRF_LOG_INFO("PWM example started.");
        init_bsp();
    
        bool accurate_HFCLK = true;
    
        if(accurate_HFCLK)
        {
          // Start accurate HFCLK (XOSC), will consume more current!
          NRF_CLOCK->TASKS_HFCLKSTART = 1;
          while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
          NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        }
    
        pwm_init();
    
    
        for (;;)
        {
            // Wait for an event.
            __WFE();
    
            // Clear the event register.
            __SEV();
            __WFE();
    
            NRF_LOG_FLUSH();
        }
    }
    
    
    /** @} */
     

Children
Related