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

Is the PWM the right solution for testing the accuracy of the crystal oscillators?

Hi,

I’m trying to test/confirm the accuracy of the 32kHz crystal oscillator and the 32MHz crystal oscillator by toggling a GPIO at a derived rate and at 50% duty.  But I’m seeing frequencies that do not appear to make sense.  Also, the tolerance range I am reading for both the HFXO and LFXO do not seem to match the electrical specifications.

I'm using the low-power PWM for the 32kHz testing and I'm using the App-PWM for the 32MHz testing.

The first bit of confusion comes from whether or not I am actually using the HFINT as opposed to the HFXO because the tolerance range of +/- 1.5%  seems to matchup with what we are reading a lot more than the +/- 40 ppm (according to the HFXO section on the electrical specifications spreadsheet).  We are using a 30ppm crystal.

The second bit of confusion is in regards to the frequency accuracy of the LFXO which seems to be most accurate (still not quite accurate enough) when set to the maximum frequency (255 ticks).  Should this crystal be more accurate than the recorded values reflect? Also, why does the duty cycle change for each different tick rate when I am always manually setting the duty cycle to 50% after setting the frequency?

For reference, I am the nrf52832  with SDK version 17.0.2. The SoftDevice is enabled and running during the tests.

LFXO

Ticks 255 163 100 78
  Expected Actual Expected Actual Expected Actual Expected Actual
Duty Cycle 50% 79.47% 50% 67.86% 50% 50% 50% 39.40%
Period (ms) 15.563965 16.05 9.94873 6.8357 6.1 2.929602 4.7607 2.014216
Frequency (Hz) 64.25 62.29 100.52 146.2891 163.84 341.3412 210.05 496.468

HFXO

Duty Cycle 50%
Period (ms) 10.04 - 10.05
Frequency (Hz) 99.4 - 99.5

/* Frequency of crystal oscillator PWM */
#define PWM_DEFAULT_FREQ_IN_HZ          100u
#define PWM_PERIOD_IN_US(hz)            (uint16_t)((1.0 / (float)hz) * 1000000)
/* Period of crystal oscillator low power PWM */
#define LOW_POWER_PWM_TICKS             100u                 // This value was changed according to attached spreadsheet

/* The current frequency of the crystal oscillator PWM */
APP_STATIC uint32_t pwm_frequency_hz_u32 = PWM_DEFAULT_FREQ_IN_HZ;

nrfx_err_t XTAL_hfclk_init(void)
{
    nrfx_err_t err_code = NRFX_SUCCESS;
    app_pwm_config_t xtal_pwm_config = APP_PWM_DEFAULT_CONFIG_1CH(PWM_PERIOD_IN_US(pwm_frequency_hz_u32), DEBUG_TEST_PIN);

    /* Set PWM polarity */
    xtal_pwm_config.pin_polarity[PWM_CHANNEL_XTAL_DRIVE] = APP_PWM_POLARITY_ACTIVE_HIGH;

    if (!xtal_hfclk_is_init_b)
    {
        /* Initialize the PWM */
        err_code = app_pwm_init(&xtal_pwm, &xtal_pwm_config, XTAL_hfclk_pwm_callback);

        if (NRFX_SUCCESS == err_code)
        {
            xtal_hfclk_is_init_b = true;
        }
        else
       {
            /* Uninitialize the PWM */
            (void)app_pwm_uninit(&xtal_pwm);
        }
    }
    else
    {
        err_code = NRFX_ERROR_ALREADY_INITIALIZED;
    }
    return err_code;
}
nrfx_err_t XTAL_hfclk_start(void)
{
    nrfx_err_t err_code = NRFX_SUCCESS;

    if (xtal_hfclk_is_init_b)
    {
        /* Start the PWM */
        app_pwm_enable(&xtal_pwm);

        /* Set the initial duty cycle */
        pwm_ready_to_set_duty_b = true;
        XTAL_hfclk_set_duty_cycle(50u);
    }
    else
    {
        err_code = APP_GENERAL_NOT_INITIALIZED_ERROR;
    }

    if (NRFX_SUCCESS == err_code)
    {
        /* Set the event flags */
        event_xtal_hfclk_started_b = true; 
        hfclk_event_pending_b = true;
    }
    return err_code;
}

nrfx_err_t XTAL_lfclk_init(void)
{
    nrfx_err_t err_code = NRFX_SUCCESS;
    low_power_pwm_config_t xtal_low_power_pwm_config = LOW_POWER_PWM_DEFAULT_CONFIG(XTAL_LFCLK_TEST_PIN_MASK);
    xtal_low_power_pwm_config.period = LOW_POWER_PWM_TICKS;

    if (!xtal_lfclk_is_init_b)
    {
        /* Initialize the PWM */
        err_code = low_power_pwm_init(&xtal_low_power_pwm, &xtal_low_power_pwm_config, NULL);

        if (NRFX_SUCCESS == err_code)
        {
            xtal_lfclk_is_init_b = true;
        }
        else
        {
            /* Do nothing */
        }
    }
    else
    {
        err_code = NRFX_ERROR_ALREADY_INITIALIZED;
    }
    return err_code;
}

nrfx_err_t XTAL_lfclk_start(void)
{
    nrfx_err_t err_code = NRFX_SUCCESS;

    if (xtal_lfclk_is_init_b)
    {
        /* Start the PWM */
        err_code = low_power_pwm_start(&xtal_low_power_pwm, XTAL_LFCLK_TEST_PIN_MASK);

        XTAL_lfclk_set_duty_cycle(50u);
    }
    else
    {
        err_code = APP_GENERAL_NOT_INITIALIZED_ERROR;
    }

    if (NRFX_SUCCESS == err_code)
    {
        /* Set the event flags */
        event_xtal_lfclk_started_b = true; 
        lfclk_event_pending_b = true;
    }
    return err_code;
}

Parents Reply Children
No Data
Related