Using PPI to Generate 8MHZ Signal

Hi,

I'm using the PPI component to generate 8MHz GPIO signal. this signal is an input for power amplifier analog RF transmitter.

While the digital 8MHz signal looks fine, we are noticing some bumps every 40 us in the RF analog signal. when trying to use the SPI clock to create the 8MHz signal the bumps are eliminated and we get a clean signal.

As the PPI input clock is 16MHz, I was wondering if theoretically its capable to create a digital 8MHz signal? that means that the GPIO should be toggled every single clock, is that an overkill in terms of performance for the PPI or should it be able to handle this task?

The bumps were also reproduced with the DK evaluation board to generate the 8MHz signal, see bump in the image below:

  • This is the code that I used to generate the 8MHz pulse:

    void hal_pulse_generator_gen(uint8_t pulse_width_us)
    {
        uint32_t pulse_width_ticks = nrf_timer_us_to_ticks(pulse_width_us, NRF_TIMER_FREQ_16MHz);
        uint32_t ltc_en_ticks = nrf_timer_us_to_ticks(LTC_ENABLE_DURATION_US, NRF_TIMER_FREQ_16MHz);
        uint32_t ppi_mask;

        nrf_timer_task_trigger(pwm_timer, NRF_TIMER_TASK_STOP);
        nrf_timer_task_trigger(pulse_timer, NRF_TIMER_TASK_STOP);
        nrf_timer_task_trigger(pulse_timer, NRF_TIMER_TASK_CLEAR);

        /* setup HF PWM timer */
        nrf_timer_mode_set(pwm_timer, NRF_TIMER_MODE_TIMER);
        nrf_timer_prescaler_set(pwm_timer, 0);
        nrf_timer_bit_width_set(pwm_timer, NRF_TIMER_BIT_WIDTH_16);
        nrf_timer_shorts_enable(pwm_timer, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);

        /* setup HF pulse timer */
        nrf_timer_mode_set(pulse_timer, NRF_TIMER_MODE_TIMER);
        nrf_timer_prescaler_set(pulse_timer, 0);
        nrf_timer_bit_width_set(pulse_timer, NRF_TIMER_BIT_WIDTH_16);
        nrf_timer_shorts_enable(pulse_timer, NRF_TIMER_SHORT_COMPARE1_STOP_MASK);

        /* clear PPI used */
        ppi_mask = BIT(ppi_chs[0]) | BIT(ppi_chs[1]) | BIT(ppi_chs[2]) | BIT(ppi_chs[3]) |
                   BIT(ppi_chs[4]) | BIT(ppi_chs[5]);
        nrfx_gppi_channels_disable(ppi_mask);

        /* configure PWM TIMER */
        nrf_timer_event_clear(pwm_timer, nrf_timer_compare_event_get(1));
        nrf_timer_event_clear(pwm_timer, nrf_timer_compare_event_get(0));
        nrf_timer_cc_set(pwm_timer, 1, 1);
        nrf_timer_cc_set(pwm_timer, 0, 2);
        nrf_timer_task_trigger(pwm_timer, NRF_TIMER_TASK_CLEAR);

        /* configure pulse TIMER */
        nrf_timer_event_clear(pulse_timer, nrf_timer_compare_event_get(3));
        nrf_timer_event_clear(pulse_timer, nrf_timer_compare_event_get(2));
        nrf_timer_event_clear(pulse_timer, nrf_timer_compare_event_get(1));
        nrf_timer_event_clear(pulse_timer, nrf_timer_compare_event_get(0));
        nrf_timer_task_trigger(pulse_timer, NRF_TIMER_TASK_CLEAR);

        /* configure PWM GPIOTE - toggle task with proper initial output value. */
        pwm_gpiote.p_reg->CONFIG[toggle_pwm_gpiote_ch] =
            (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
            ((uint32_t)pwm_psel_ch << GPIOTE_CONFIG_PSEL_Pos) |
            (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) |
            ((uint32_t)pwm_initial_value << GPIOTE_CONFIG_OUTINIT_Pos);

        /* configure LTC enable GPIOTE - set task with proper initial output value. */
        ltc_en_gpiote.p_reg->CONFIG[ltc_en_gpiote_ch] =
            (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
            ((uint32_t)ltc_en_psel_ch << GPIOTE_CONFIG_PSEL_Pos) |
            (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) |
            ((uint32_t)ltc_en_initial_value << GPIOTE_CONFIG_OUTINIT_Pos);

        /* setup PWM PPI */
        uint32_t pwm_pulse_end_event_address, pwm_period_end_event_address;
        nrf_gpiote_task_t pwm_pulse_end_task, pwm_period_end_task;
    #if defined(GPIOTE_FEATURE_SET_PRESENT) && defined(GPIOTE_FEATURE_CLR_PRESENT)
        if (pwm_initial_value == 0) {
            pwm_pulse_end_task = nrf_gpiote_set_task_get(toggle_pwm_gpiote_ch);
            pwm_period_end_task = nrf_gpiote_clr_task_get(toggle_pwm_gpiote_ch);
        } else {
            pwm_pulse_end_task = nrf_gpiote_clr_task_get(toggle_pwm_gpiote_ch);
            pwm_period_end_task = nrf_gpiote_set_task_get(toggle_pwm_gpiote_ch);
        }
    #else
        pwm_pulse_end_task = pwm_period_end_task = nrf_gpiote_out_task_get(toggle_pwm_gpiote_ch);
    #endif

        uint32_t pwm_pulse_end_task_address =
            nrf_gpiote_task_address_get(pwm_gpiote.p_reg, pwm_pulse_end_task);
        uint32_t pwm_period_end_task_address =
            nrf_gpiote_task_address_get(pwm_gpiote.p_reg, pwm_period_end_task);

        pwm_period_end_event_address =
            nrf_timer_event_address_get(pwm_timer, nrf_timer_compare_event_get(0));
        pwm_pulse_end_event_address =
            nrf_timer_event_address_get(pwm_timer, nrf_timer_compare_event_get(1));

        nrfx_gppi_channel_endpoints_setup(ppi_chs[0], pwm_pulse_end_event_address,
                                          pwm_pulse_end_task_address);
        nrfx_gppi_channel_endpoints_setup(ppi_chs[1], pwm_period_end_event_address,
                                          pwm_period_end_task_address);

        /* setup pulse PPI */
        uint32_t pulse_start_event_address;
        uint32_t pulse_end_event_address;
        uint32_t ltc_en_end_event_address;
        uint32_t pulse_sample_ltc_event_address;

        uint32_t pulse_start_task_address = nrf_timer_task_address_get(pwm_timer, NRF_TIMER_TASK_START);
        uint32_t pulse_end_task_address = nrf_timer_task_address_get(pwm_timer, NRF_TIMER_TASK_STOP);
        nrf_gpiote_task_t ltc_en_end_task = nrf_gpiote_out_task_get(ltc_en_gpiote_ch);
        uint32_t ltc_en_end_task_address =
            nrf_gpiote_task_address_get(ltc_en_gpiote.p_reg, ltc_en_end_task);
        uint32_t ltc_sample_task_address = nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);

        pulse_start_event_address =
            nrf_timer_event_address_get(pulse_timer, nrf_timer_compare_event_get(0));
        pulse_end_event_address =
            nrf_timer_event_address_get(pulse_timer, nrf_timer_compare_event_get(1));
        ltc_en_end_event_address =
            nrf_timer_event_address_get(pulse_timer, nrf_timer_compare_event_get(2));
        pulse_sample_ltc_event_address =
            nrf_timer_event_address_get(pulse_timer, nrf_timer_compare_event_get(3));

        nrfx_gppi_channel_endpoints_setup(ppi_chs[2], pulse_start_event_address,
                                          pulse_start_task_address);
        nrfx_gppi_channel_endpoints_setup(ppi_chs[3], pulse_end_event_address, pulse_end_task_address);
        nrfx_gppi_channel_endpoints_setup(ppi_chs[4], ltc_en_end_event_address,
                                          ltc_en_end_task_address);
        nrfx_gppi_channel_endpoints_setup(ppi_chs[5], pulse_sample_ltc_event_address,
                                          ltc_sample_task_address);

        /* enable PPI */
        nrfx_gppi_channels_enable(ppi_mask);

        nrf_timer_cc_set(pulse_timer, 3,
                         ltc_en_ticks + nrf_timer_us_to_ticks(20U, NRF_TIMER_FREQ_16MHz));
        nrf_timer_cc_set(pulse_timer, 2, ltc_en_ticks + pulse_width_ticks);
        nrf_timer_cc_set(pulse_timer, 1, ltc_en_ticks + pulse_width_ticks);
        nrf_timer_cc_set(pulse_timer, 0, ltc_en_ticks);

        last_ltc_sample = 0;

        /* start timers */
        nrf_timer_task_trigger(pulse_timer, NRF_TIMER_TASK_START);

        return;
    }
  • Hello Joshua,

    I'll have to get back to you on this tomorrow.

    You are using the 5340?

    Are these bumps a problem for your application?

    Regards,

    Elfving

  • The slope of it seems even more odd to me, was that somehow intentional from you?

    Are you seeing the same bumps without it being turned off and on this frequently?

    Just noticed that you've added code here in a reply. I'll see if I can reproduce this on my side.

    Regards,

    Elfving

  • Hi,

    the slope is a side-effect of some HW current protection we have, its not a problem for us.

    Thanks 

Related