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

nRF52840 - giving userdefined function at PPI task end

Hello,

We were just wondering if it is possible to give user-defined function at the PPI TEP instead of starting timer or generating some GPIOTE task.

Is it possible to configure a PPI channel where there is a GPIOTE event and as per the occurrence of that event, some userdefined function executes?

nrf_drv_ppi_channel_assign(m_ppi_channel1,
                           gpiote_event_addr,
                           &user_defined_function);

I tried above way, it compiled but the function is not getting executed on GPIOTE event.

I can't use the timer interrupt for this as the frequency of GPIOTE event is really high (around 3MHz). And I want to capture 8-bit parallel port data in 'user_defined_function'

So, Can I make above logic work anyhow? Is it possible in PPI? Any suggestions how can I achieve this one?

Thanks in advance.

Parents Reply Children
  • See the attached project. It should work in SDK15.3.0. 

    It is a bare-metal approach for PWM using GPIOTE, TIMER and PPI. I changed one of the pins to trigger an EGU to get a callback and toggle the pin instead of toggling directly from the GPIOTE. 

    Note that there aren't any EGU drivers, so I think this bare-metal approach is the best I can give.

    PS: it is a modified blinky project. Since it doesn't use any drivers, it should work by replacing the main.c file in any SDK example.PPI_EGU_example.zip

    Best regards,

    Edvin

  • Thanks for the demo code,

    I used in my application and it works as expected. However while debugging in Segger Embedded Studio we found something interesting. 

    void SWI1_EGU1_IRQHandler(void)
    {
        ++m_counter;
    }
    
    void egu_init(void)
    {
        NVIC_ClearPendingIRQ(SWI1_EGU1_IRQn);
        NVIC_EnableIRQ(SWI1_EGU1_IRQn);
        NRF_EGU1->INTENSET = (1 << 0) | (1 << 1);
    }
    
    static void ppi_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
        nrf_drv_gpiote_in_config_t config = NRFX_GPIOTE_RAW_CONFIG_IN_SENSE_LOTOHI(true);
        config.pull = NRF_GPIO_PIN_NOPULL;
        uint32_t gpiote_event_addr;
        nrfx_gpiote_uninit();
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
        //nrfx_gpiote_in_uninit(PIN_NUMBER);
    
        /* Configure 1st available PPI channel to stop TIMER0 counter on TIMER1 COMPARE[0] match,
         * which is every even number of seconds.
         */
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_gpiote_in_init(PIN_NUMBER, &config, gpiote_event_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_NUMBER, false);
    
        gpiote_event_addr = nrf_drv_gpiote_in_event_addr_get(PIN_NUMBER);
    
    
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1,
                                              gpiote_event_addr,
                                              (uint32_t)&NRF_EGU1->TASKS_TRIGGER[0]);
    
        APP_ERROR_CHECK(err_code);
    
        NRF_PPI->CHENSET                 = (1 << m_ppi_channel1);
    }

    Above is the code snippet which we made by the help of the demo you share. Below is our observation:

    • The egu_init() is successful. ppi_init is also successful.
    • When the routine of ppi_init get's completed specially when ppi channel is enabled, the code gets stuck (I guess in IRQHandler) and m_counter keeps on increment. The thing to be noted is there is continuous input event on the GPIO configured in GPIOTE at the frequency of 1MHz.

    Is this a expected behaviour? As we have another logic to be performed after ppi_init, we might not want to get stuck in IRQHandler. Is there any configuration which we missed? or am I understanding it incorrectly?

    Thanks

  • I am not sure, but I think I saw something similar when I tested the project that I sent you.

    I thought that it stopped the other PPI events from happening (LED1 stopped, but LED2 kept on blinking). I figured this was because the EGU triggered too often, so that the application layer never got any time to update the TIMER->CC[] registers. If you have interruptions at 1MHz, then you don't have many clock cycles to run your SWI_EGU1_IRQHandler() before the interrupt triggers again.

    However, I see that you don't reset the EGU event. Can you try to add:

    NRF_EGU1->TASKS_TRIGGER[0] = 0;

    in your SWI1_EGU1_IRQHandler()?

  • I added below line of code in IRQ Handler.

    NRF_EGU1->TASKS_TRIGGER[0] = 0;

    But still there is no change in behaviour. It continuously executes the IRQ handler and none of the other logic is executed.

    Is there any document for clock cycle, such that we can understand the machine cycle consumed in each instruction?

  • can you try to trigger the PPI event less often, i.e. have an input pulse with a lower frequency to see if this is actually the issue? (you can use a timer to generate a pulse on one of the GPIOs that you input to your PPI pin)

Related