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.

  • Hello,

    Sorry, the previous reply was from a spam-bot. I reported it, and the reply was deleted, along with your answer to it. 

    You can try to use EGU (event generator unit) to trigger a SW interrupt event from the PPI. To get some help to set it up, check out this ticket, and let me know if you are stuck somewhere.

  • Okay, understood the concept of EGU.

    But didn't get how to make it functional.

    Can you please provide a demo code for that? or any further reference regarding that will be useful.

    Thanks.

  • 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()?

Related