timer and ppi on nrf connect sdk

hello Nordic

i work with nrf52832, nrf52840 with ncs 1.9

i have 2 issues, is there some example or guid fo using 2 ppi channels for the same gpiote, one timer pullup the gpio and the other timer pulls the same gpio down .. what functions are a must ?  gpioite_channel allocation is a must or ppi_channel_allocations are enough etc.

second issue is that i use three timers in my code and it looks like one of them does not work ok, 

also if i look at pin toggle in ppk power profiler i see that if i light a led while the sampling then i the gpio (pulled up by ppi and pulled down by spi_done handler) sometimes miss some toggling every some time .. any ideas why ?

hope to read from you soon

best regards

Ziv

Parents
  • Hi,

    i have 2 issues, is there some example or guid fo using 2 ppi channels for the same gpiote, one timer pullup the gpio and the other timer pulls the same gpio down .. what functions are a must ?  gpioite_channel allocation is a must or ppi_channel_allocations are enough etc.

    You will have to define one GPIOTE channel and tow PPI channels. One PPI channel will connect to the TASKS_SET[n] register of the GPIOTE, and the other PPI channel will connect to TASKS_CLR[n].

    second issue is that i use three timers in my code and it looks like one of them does not work ok, 

    Can you elaborate more on what is not working? How do you configure/use the timers? Note that some timer instances are used by protocol stacks (BLE/Thread/Zigbee, etc) if that is used.

    also if i look at pin toggle in ppk power profiler i see that if i light a led while the sampling then i the gpio (pulled up by ppi and pulled down by spi_done handler) sometimes miss some toggling every some time .. any ideas why ?

    Hard to say without more details. Will both set and clear be missed, or only clearing from the spi_done event? In that case it could be some interrupt issues, for instance the interrupt is blocked by other high-priority tasks. Please also post your code to show how the PPI is configured and how you clear the pin in the spi handler.

    Best regards,
    Jørgen

Reply
  • Hi,

    i have 2 issues, is there some example or guid fo using 2 ppi channels for the same gpiote, one timer pullup the gpio and the other timer pulls the same gpio down .. what functions are a must ?  gpioite_channel allocation is a must or ppi_channel_allocations are enough etc.

    You will have to define one GPIOTE channel and tow PPI channels. One PPI channel will connect to the TASKS_SET[n] register of the GPIOTE, and the other PPI channel will connect to TASKS_CLR[n].

    second issue is that i use three timers in my code and it looks like one of them does not work ok, 

    Can you elaborate more on what is not working? How do you configure/use the timers? Note that some timer instances are used by protocol stacks (BLE/Thread/Zigbee, etc) if that is used.

    also if i look at pin toggle in ppk power profiler i see that if i light a led while the sampling then i the gpio (pulled up by ppi and pulled down by spi_done handler) sometimes miss some toggling every some time .. any ideas why ?

    Hard to say without more details. Will both set and clear be missed, or only clearing from the spi_done event? In that case it could be some interrupt issues, for instance the interrupt is blocked by other high-priority tasks. Please also post your code to show how the PPI is configured and how you clear the pin in the spi handler.

    Best regards,
    Jørgen

Children
  • ok .. 

    a bit different approach that i am trying .. i wish to have the same timer compare the SET, without clearing the timer and then the second compare event for the CLR will clear the timer (so for example first compare will be for 80 microsec, the second compare will be for 100 microsec and then clearing the timer so actually both events happen every 100 microsec with a small shift between them)

    any idea how to do it ?

    hope to read from you soon

    best regards

    Ziv

  • ziv123 said:

    a bit different approach that i am trying .. i wish to have the same timer compare the SET, without clearing the timer and then the second compare event for the CLR will clear the timer (so for example first compare will be for 80 microsec, the second compare will be for 100 microsec and then clearing the timer so actually both events happen every 100 microsec with a small shift between them)

    any idea how to do it ?

    This should not be a problem.

    You configure the timer using COMPARE0 and COMPARE1 events, each connected to one of the PPI channels. Then you enable the timer SHORT->COMPARE1_CLEAR, which will clear the timer only after the second compare event.

  • hi again

    few notes on that .. first the order of the channels seems to be important (if i set ch1 as the first compare and then ch0 is the later compare with clear task it did not work, did not make sense that this will be dependent and maybe there is a different reason but this worked and the other did not ) , correct me if i am wrong. 

    when i try to also add a compare event that will call a timer handler then nothing happens and i am not sure why 

    i have this code if i change from true to false on the compare of ch2 then it works, but trying to make the compare trigger the interrupt does not work for some reason

    nrfx_timer_config_t timer_cfg = {
            .frequency = NRF_TIMER_FREQ_16MHz,
            .mode = NRF_TIMER_MODE_TIMER,
            .bit_width = NRF_TIMER_BIT_WIDTH_32,
            .p_context = NULL,
        };
    
        int res = nrfx_timer_init(timer, &timer_cfg, dummy_timer_handler);
        if (res != NRFX_SUCCESS)
        {
            AUGU_LOG_ERR("error in nrfx_timer_init %x", res);
            return -EINVAL;
        }
    
        nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, 1, false);
        uint32_t compar_val = nrfx_timer_us_to_ticks(timer, 2);
        nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL1, compar_val, false);
        compar_val = nrfx_timer_us_to_ticks(timer, 20);
        nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL2, compar_val, true);
        compar_val = nrfx_timer_us_to_ticks(timer, 1000000 / sample_freq);
        nrfx_timer_extended_compare(timer, NRF_TIMER_CC_CHANNEL3, compar_val, NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK, false);
    
        *time_conv_up = nrfx_timer_compare_event_address_get(timer, NRF_TIMER_CC_CHANNEL0);
        *time_spi_xfer = nrfx_timer_compare_event_address_get(timer, NRF_TIMER_CC_CHANNEL1);
     

    i also tried to use another timer to call on a handler once compare value is reached and for some reason the handler is not called. this is the timer initialisation config and the handler code:

    {
                    ...
                    nrfx_timer_config_t timer_cfg = {
                        .frequency = NRF_TIMER_FREQ_16MHz,
                        .mode = NRF_TIMER_MODE_TIMER,
                        .bit_width = NRF_TIMER_BIT_WIDTH_32,
                        .p_context = NULL,
                    };
    
                    int res = nrfx_timer_init(&timer_cycle_done, &timer_cfg, dummy_timer_handler1);
                    if (res != NRFX_SUCCESS)
                    {
                        AUGU_LOG_ERR("error in nrfx_timer_init %x", res);
                        return -EINVAL;
                    }
    
                    uint32_t compar_val = nrfx_timer_us_to_ticks(&timer_cycle_done, 1000000 / drv_data->sample_frequency);
                    nrfx_timer_extended_compare(&timer_cycle_done, NRF_TIMER_CC_CHANNEL0, compar_val, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
                    nrfx_timer_compare_int_enable(&timer_cycle_done, NRF_TIMER_CC_CHANNEL0);
                    
                    nrfx_timer_enable(&timer_cycle_done);
                    ...
    }
    
    static void dummy_timer_handler1(nrf_timer_event_t event_type, void *p_context)
    {
        // gpio_pin_set(gpio_dev_red, 25, 1);
        gpio_pin_toggle(gpio_dev_red, 25);
    }

    also on that code, it is not clear if i need to use the ' nrfx_timer_compare_int_enable ' if i put true in the ' 

    nrfx_timer_extended_compare ' function args ?
    hope to read from you soon
    best regards
    Ziv
  • Hi,

    ziv123 said:
    first the order of the channels seems to be important (if i set ch1 as the first compare and then ch0 is the later compare with clear task it did not work, did not make sense that this will be dependent and maybe there is a different reason but this worked and the other did not ) , correct me if i am wrong. 

    No, it should not be a problem to have a higher channel set to a shorter CC value. Each CC value should be evaluated against the count independently of other channels by the hardware. I tested that it works well to set COMPARE0 with a higher CC value than COMPARE1 in the timer example in nRF5 SDK on nRF52832. Please check the registers with a debugger to make sure the CC values and shortcuts are set as you intended.

    ziv123 said:

    when i try to also add a compare event that will call a timer handler then nothing happens and i am not sure why 

    i have this code if i change from true to false on the compare of ch2 then it works, but trying to make the compare trigger the interrupt does not work for some reason

    This sounds strange. If you set the enable_int parameter to false, the interrupt/handler should not be called, it should only work if you set it to true. Can you check with a debugger if the INTEN register have the COMPARE2 enabled or not?

    ziv123 said:
    i also tried to use another timer to call on a handler once compare value is reached and for some reason the handler is not called. this is the timer initialisation config and the handler code:

    Have you remembered to connect the TIMER interrupt using the Zephyr API? IRQ_CONNECT()

    ziv123 said:

    also on that code, it is not clear if i need to use the ' nrfx_timer_compare_int_enable ' if i put true in the ' 

    nrfx_timer_extended_compare ' function args ?

    No, this is not necessary, the same functions are called inside nrfx_timer_extended_compare() if enable_int is set to true. This function can be used if you want to enable interrupts at a different point in your code than where you configure the compare registers.

    Best regards,
    Jørgen

  • Hi

    Have you remembered to connect the TIMER interrupt using the Zephyr API? IRQ_CONNECT()

    i haven't done that, i also wonder if i can use IRQ_DIRECT_CONNECT if i will need more real time performance? 

    but before that, i m not sure if the instance number i give to the timer dictates which timer i am working with .. meaning if 

    #define CONFIG_ADS8866_CHAIN_XFER_TIMER_INST 2
    static const nrfx_timer_t timer_cycle_done = NRFX_TIMER_INSTANCE(CONFIG_ADS8866_CHAIN_XFER_TIMER_INST);
    
    and initialisation looks like so :

     

    rfx_timer_config_t timer_cfg = {
            .frequency = NRF_TIMER_FREQ_16MHz,
            .mode = NRF_TIMER_MODE_TIMER,
            .bit_width = NRF_TIMER_BIT_WIDTH_32,
            .p_context = handler_context,
        };
    
        int res = nrfx_timer_init(timer, &timer_cfg, ads8866_spi_done_event_handler);
        if (res != NRFX_SUCCESS)
        {
            AUGU_LOG_ERR("error in nrfx_timer_init %x", res);
            return -EINVAL;
        }
        IRQ_DIRECT_CONNECT(TIMER2_IRQn, 0, nrfx_timer_2_irq_handler, 0);

    but i had to try &error to see if it is TIMER1_IRQ / TIMER2_IRQ / TIMER0_IRQ

    is there a way to know in advance, also what if i use instance 4 of a timer ?

    best regards

    Ziv

Related