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

I have tried to produce a PWM signal of 33.33KHz at a GPIO pin of nRF52832!The duty cycle of the signal varies bizzaredly even after setting it to 50%!Can anyone help me out! I wanna run an external IC on this clock!Please find the screenshot attached!

PWM.PNGHere is my code:

#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"
#include "boards.h"
#include "app_error.h"
#include <stdint.h>
#include <stdbool.h>

#define COMPARE_COUNTERTIME  (3UL)                                       < Get Compare event COMPARE_TIME seconds after the counter starts from 0.

#ifdef  BSP_LED_0
    #define TICK_EVENT_OUTPUT    BSP_LED_0                        < Pin number for indicating tick event. 
#endif
#ifndef TICK_EVENT_OUTPUT
    #error "Please indicate output pin"
#endif
#ifdef BSP_LED_1
    #define COMPARE_EVENT_OUTPUT   BSP_LED_1                               < Pin number for indicating compare event.
#endif
#ifndef COMPARE_EVENT_OUTPUT
    #error "Please indicate output pin"
#endif

const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); //< Declaring an instance of nrf_drv_rtc for RTC0. 

/** @brief: Function for handling the RTC0 interrupts.
 * Triggered on TICK and COMPARE0 match.
 */
static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{    nrf_gpio_pin_toggle(10);
    if (int_type == NRF_DRV_RTC_INT_COMPARE0)
    {
        nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
    }
    else if (int_type == NRF_DRV_RTC_INT_TICK)
    {
        nrf_gpio_pin_toggle(17);
    }
}

/** @brief Function configuring gpio for pin toggling.
 */
static void leds_config(void)
{
    bsp_board_leds_init();
}

/** @brief Function starting the internal LFCLK XTAL oscillator.
 */
static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_clock_lfclk_request(NULL);
}

/** @brief Function initialization and configuration of RTC driver instance.
 */
static void rtc_config(void)
{
    uint32_t err_code;

    //Initialize RTC instance
    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    config.prescaler =0;
    err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
    APP_ERROR_CHECK(err_code);

    //Enable tick event & interrupt
    nrf_drv_rtc_tick_enable(&rtc,true);

    //Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
    err_code = nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * 8,true);
    APP_ERROR_CHECK(err_code);

    //Power on RTC instance
    nrf_drv_rtc_enable(&rtc);
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    leds_config();

    lfclk_config();

    rtc_config();

    while (true)
    {
        __SEV();
        __WFE();
        __WFE();
    }
}
Parents
  • Hi,

    I recommend that you use the PWM peripheral for this.

    The code below will give you a 33.33 KHz clock at 50 % duty at pin 4.

    #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
    
    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
    };
    
    
    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    = 30,
            
            //F(pwm) = F(clk)/top_value
            
            
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        
        seq_values->channel_0 = 15;
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
        
    }
    
    
    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();
    
        for (;;)
        {
            
        }
    }
    
  • Hi,

    All the driver API is documented at infocenter here.

    Since you need 33.33KHz you need to use the HFCLK anyway. The low-power PWM library that uses the LFCLK have a max frequency around 6kHz.

    To save power, add this to the loop to put the CPU to sleep:

    for (;;)
    {
        // Use directly __WFE and __SEV macros since the SoftDevice is not available.
        // Wait for event.
        __WFE();
    
        // Clear Event Register.
        __SEV();
        __WFE();
    }
    

    you could also remove the code in start of main(), i.e. the NRF_CLOCK->TASKS_HFCLKSTART = 1; and while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);. Then you will be using the HFINT(internal HF RC) instead of the HF crystal oscillator(HFXO), you will get lower power consumption with HFINT. With this, I'm measuring around 680 µA.

Reply
  • Hi,

    All the driver API is documented at infocenter here.

    Since you need 33.33KHz you need to use the HFCLK anyway. The low-power PWM library that uses the LFCLK have a max frequency around 6kHz.

    To save power, add this to the loop to put the CPU to sleep:

    for (;;)
    {
        // Use directly __WFE and __SEV macros since the SoftDevice is not available.
        // Wait for event.
        __WFE();
    
        // Clear Event Register.
        __SEV();
        __WFE();
    }
    

    you could also remove the code in start of main(), i.e. the NRF_CLOCK->TASKS_HFCLKSTART = 1; and while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);. Then you will be using the HFINT(internal HF RC) instead of the HF crystal oscillator(HFXO), you will get lower power consumption with HFINT. With this, I'm measuring around 680 µA.

Children
No Data
Related