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

PPI Auto Reset Timer In Counter Mode

  // motion frequency capture
  NRF_PPI->CH[CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE].EEP = CFG_TASKER_PIF_TIMER->EVENTS_COMPARE[1]; // wire timer compare
  NRF_PPI->CH[CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE].TEP = CFG_MOTION_PIF_TIMER->TASKS_CAPTURE[1]; // wire ppi to timer capture
  NRF_PPI->CH[CFG_PPI_TASKER_CHANNEL_MOTION_CLEAR].EEP = CFG_TASKER_PIF_TIMER->EVENTS_COMPARE[1]; // wire timer compare
  NRF_PPI->CH[CFG_PPI_TASKER_CHANNEL_MOTION_CLEAR].TEP = CFG_MOTION_PIF_TIMER->TASKS_CLEAR; // wire ppi to reset count
  NRF_PPI->CHENSET = 1 << CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE_POS;  // enable ppi channel
  NRF_PPI->CHENSET = 1 << CFG_PPI_TASKER_CHANNEL_MOTION_CLEAR_POS;  // enable ppi channel



The only way I can see to do it is by two separate PPI calls. So Timer1 "tasker" is firing both the capture and clear... but will they execute sequentially?

Parents
  • Hello,

    If you capture and clear at the same time, then you have a chance of capturing 0. PPI tasks are done by HW directly, so it will not wait for the capture to finish before clearing.

    I am not sure exactly what your timer is doing, but often when this question comes up it usually turns out that the clearing of the timer is not strictly necessary. And why do you need to capture when you know the value of the timer? (It clears when it reaches the set value, right?)

    Best regards,

    Edvin

  • No, I'm capturing pulses for frequency measurement.  The code below may explain better.

    It sounds like PPI or FORK can't guarantee the logic, so I'll have to have code to subtract the previous value plus manage a wrap around condition. Best approach?

      // tasker fires every 500ms
      
      // motion frequency capture
      NRF_PPI->CH[CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE].EEP = CFG_TASKER_PIF_TIMER->EVENTS_COMPARE[1]; // wire timer compare
      NRF_PPI->CH[CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE].TEP = CFG_MOTION_PIF_TIMER->TASKS_CAPTURE[1]; // wire ppi to timer capture
      NRF_PPI->FORK[CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE].TEP = CFG_MOTION_PIF_TIMER->TASKS_CLEAR; // wire ppi to reset count
      NRF_PPI->CHENSET = 1 << CFG_PPI_TASKER_CHANNEL_MOTION_CAPTURE_POS;  // enable ppi channel
    
      // motion pin
      NRF_GPIOTE->CONFIG[CFG_GPIOTE_MOTION_CHANNEL] = (CFG_PIN_MOTION_ZEROCROSS << GPIOTE_CONFIG_PSEL_Pos) | (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos) | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
      NRF_PPI->CH[CFG_PPI_MOTION_CHANNEL_COUNT].EEP = NRF_GPIOTE->EVENTS_IN[CFG_GPIOTE_MOTION_CHANNEL]; // wire gpio event to ppi
      NRF_PPI->CH[CFG_PPI_MOTION_CHANNEL_COUNT].TEP = CFG_MOTION_PIF_TIMER->TASKS_COUNT; // wire ppi to timer count
      NRF_PPI->CHENSET = 1 << CFG_PPI_MOTION_CHANNEL_COUNT_POS;  // enable ppi channel




  • I see. Yes. For pulse length measurement I would suggest to subtract the previous measurement. If you set the timer in 32bit mode (instead of default 24 bit), you don't really need to worry about wraparound at all.

    uint32_t a = 0x0000 0001
    uint32_t b = 0xFFFF FFFF
    
    uint32_t c = a-b; // c = 0x0000 0002

    In C programming this operation will automatically wrap around, so as long as the pulse is not longer than one full clock cycle (which is unlikely), you don't need to worry about the wrap around. 

    So you can remove the fork: CFG_MOTION_PIF_TIMER->TASKS_CLEAR;

    I am a bit confused about your counter mode timer, and how that works in your application, but it may be working. I am just used to seeing a timer being used directly, and capturing the CC of a timer mode timer on a hitolo/lotohi. However, when you read out the capture value, compare it to the previous capture compare value, and this should give the difference. Something like this (pseudo):

    volatile uint32_t prev_capture = 0x00;
    volatile uint32_t curr_capture = 0x00;
    
    void timer_interrupt_handler(void)
    {
        curr_capture = TIMERX->CC[1];
        uint32_t diff_capture = curr_capture - prev_capture;
        NRF_LOG_INFO("diff_capture %08x", diff_capture);
        prev_capture = curr_capture;
    }

    Best regards,

    Edvin

Reply
  • I see. Yes. For pulse length measurement I would suggest to subtract the previous measurement. If you set the timer in 32bit mode (instead of default 24 bit), you don't really need to worry about wraparound at all.

    uint32_t a = 0x0000 0001
    uint32_t b = 0xFFFF FFFF
    
    uint32_t c = a-b; // c = 0x0000 0002

    In C programming this operation will automatically wrap around, so as long as the pulse is not longer than one full clock cycle (which is unlikely), you don't need to worry about the wrap around. 

    So you can remove the fork: CFG_MOTION_PIF_TIMER->TASKS_CLEAR;

    I am a bit confused about your counter mode timer, and how that works in your application, but it may be working. I am just used to seeing a timer being used directly, and capturing the CC of a timer mode timer on a hitolo/lotohi. However, when you read out the capture value, compare it to the previous capture compare value, and this should give the difference. Something like this (pseudo):

    volatile uint32_t prev_capture = 0x00;
    volatile uint32_t curr_capture = 0x00;
    
    void timer_interrupt_handler(void)
    {
        curr_capture = TIMERX->CC[1];
        uint32_t diff_capture = curr_capture - prev_capture;
        NRF_LOG_INFO("diff_capture %08x", diff_capture);
        prev_capture = curr_capture;
    }

    Best regards,

    Edvin

Children
No Data
Related