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

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

Reply Children
Related