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

howto: get accurate 800KHz on a GPIO pin without blocking other timer-sensitive operations

Using 52840, I would like to drive an ADC chip - and it needs to get 800KHz. sampling speed (800/16=50KHz) should be accurate

* a timer isn't an option - not accurate enough

* PWM provides the period in uSec, so 1uSec is 1MHz and 2 is 500KHz - no finer resolution is provided (?) in order to get 800KHz.

* using HFCLK (code below) works fine with an empty main() app, but blocks my application other features

Ideas?

{

  NRF_CLOCK->TASKS_HFCLKSTART = 1; // Start high frequency clock
  while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
    {
      // Wait for HFCLK to start
    }
  NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; // Clear event

  // Configure GPIOTE to toggle pin 
  NRF_GPIOTE->CONFIG[0] =
      GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
      GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
      ADC_clk << GPIOTE_CONFIG_PSEL_Pos |
      GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos;

  // Configure timer
  NRF_TIMER1->PRESCALER = 0;
  NRF_TIMER1->CC[0] = 10; // Adjust the output frequency by adjusting the CC.
  NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled
                       << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
  NRF_TIMER1->TASKS_START = 1;

  // Configure PPI
  NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0];
  NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];

  NRF_PPI->CHENSET = PPI_CHENSET_CH0_Enabled << PPI_CHENSET_CH0_Pos;


}

Parents
  • Hi,

    You can use the PWM peripheral for this.

    Here is some code that will generate 800KHz on pin 3:

    /**
     * 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.
     *
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <math.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"
    
    #define OUTPUT_PIN_1      3
    #define PWM_TOP_VALUE     10
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycles(uint32_t dc1, uint32_t dc2, uint32_t dc3, uint32_t dc4)
    {
        
        // Check if value is outside of range. If so, set to 100%
        seq_values->channel_0 = (dc1 < PWM_TOP_VALUE) ? dc1 : PWM_TOP_VALUE;
        seq_values->channel_1 = (dc2 < PWM_TOP_VALUE) ? dc2 : PWM_TOP_VALUE;
        seq_values->channel_2 = (dc3 < PWM_TOP_VALUE) ? dc3 : PWM_TOP_VALUE;
        seq_values->channel_3 = (dc4 < PWM_TOP_VALUE) ? dc4 : PWM_TOP_VALUE;
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN_1, // channel 0
                NRFX_PWM_PIN_NOT_USED,             // channel 1
                NRFX_PWM_PIN_NOT_USED,             // channel 2
                NRFX_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_8MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = PWM_TOP_VALUE,
            .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)
    {
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("PWM example started.");
    
    
        // Start clock for accurate frequencies
        NRF_CLOCK->TASKS_HFCLKSTART = 1; 
        // Wait for clock to start
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
    
        
        pwm_init();
        pwm_update_duty_cycles(5,5,5,5);
    
        for (;;)
        {
            // Wait for an event.
            __WFE();
    
            // Clear the event register.
            __SEV();
            __WFE();
    
            NRF_LOG_FLUSH();
        }
    }
    
    
    /** @} */
    

Reply
  • Hi,

    You can use the PWM peripheral for this.

    Here is some code that will generate 800KHz on pin 3:

    /**
     * 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.
     *
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <math.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"
    
    #define OUTPUT_PIN_1      3
    #define PWM_TOP_VALUE     10
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycles(uint32_t dc1, uint32_t dc2, uint32_t dc3, uint32_t dc4)
    {
        
        // Check if value is outside of range. If so, set to 100%
        seq_values->channel_0 = (dc1 < PWM_TOP_VALUE) ? dc1 : PWM_TOP_VALUE;
        seq_values->channel_1 = (dc2 < PWM_TOP_VALUE) ? dc2 : PWM_TOP_VALUE;
        seq_values->channel_2 = (dc3 < PWM_TOP_VALUE) ? dc3 : PWM_TOP_VALUE;
        seq_values->channel_3 = (dc4 < PWM_TOP_VALUE) ? dc4 : PWM_TOP_VALUE;
        
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN_1, // channel 0
                NRFX_PWM_PIN_NOT_USED,             // channel 1
                NRFX_PWM_PIN_NOT_USED,             // channel 2
                NRFX_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_8MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = PWM_TOP_VALUE,
            .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)
    {
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("PWM example started.");
    
    
        // Start clock for accurate frequencies
        NRF_CLOCK->TASKS_HFCLKSTART = 1; 
        // Wait for clock to start
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
    
        
        pwm_init();
        pwm_update_duty_cycles(5,5,5,5);
    
        for (;;)
        {
            // Wait for an event.
            __WFE();
    
            // Clear the event register.
            __SEV();
            __WFE();
    
            NRF_LOG_FLUSH();
        }
    }
    
    
    /** @} */
    

Children
Related