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

Timer capture 'noise' or sync/race condition on CC read?

Hi,

I've a timer configured by gpiote to capture with a second 'overflow' capture should the signal stop. I'm not using an interrupt instead the CC[0] value is being used elsewhere (more on that in a second). The input signal is a square wave at ~150Hz. From oscilloscope I can see there is almost zero slew and no noise at all.

  NRF_GPIO->PIN_CNF[CFG_PIN_MOTION_NUM] = PIN_MOTION_CONF;
  NRF_GPIOTE->CONFIG[CFG_GPIOTE_CHANNEL_MOTION] = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos | CFG_PIN_MOTION_NUM << GPIOTE_CONFIG_PSEL_Pos | GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos;
  CFG_TIMER_MOTION->PRESCALER = CFG_MOTION_PRESCALER << TIMER_PRESCALER_PRESCALER_Pos;
  CFG_TIMER_MOTION->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
  CFG_TIMER_MOTION->CC[1] = CFG_MOTION_ONE_SECOND >> 1;
  CFG_TIMER_MOTION->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos;
  NRF_PPI->CH[CFG_PPI_MOTION_TIMER_COMPARE].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[CFG_GPIOTE_CHANNEL_MOTION];
  NRF_PPI->CH[CFG_PPI_MOTION_TIMER_COMPARE].TEP = (uint32_t)&CFG_TIMER_MOTION->TASKS_CAPTURE[0];
  NRF_PPI->FORK[CFG_PPI_MOTION_TIMER_COMPARE].TEP = (uint32_t)&CFG_TIMER_MOTION->TASKS_CLEAR;
  NRF_PPI->CH[CFG_PPI_MOTION_TIMER_OVERFLOW].EEP = (uint32_t)&CFG_TIMER_MOTION->EVENTS_COMPARE[1];
  NRF_PPI->CH[CFG_PPI_MOTION_TIMER_OVERFLOW].TEP = (uint32_t)&CFG_TIMER_MOTION->TASKS_CAPTURE[0];
  NRF_PPI->CHENSET = 1 << CFG_PPI_MOTION_TIMER_COMPARE | 1 << CFG_PPI_MOTION_TIMER_OVERFLOW;
  CFG_TIMER_MOTION->TASKS_START = 1;


So the above runs and the timer is continuously updating the CC value.

I then have a second timer at a set frequency (currently 120Hz) which is used for PID control. It uses the CC[0] value in it's calculations however randomly the value is much lower than the real thing, as if there's noise. It's never higher from what I can tell.

The only plausible explanation I have is that while the second timer interrupt is accessing the CC[0] value the hardware may be updating it. My understanding is this is resolved normally by double buffering but I may be incorrect. Anyway, I couldn't find anything on the CC values being buffered.

Any advice much appreciated. I'd like to avoid copying the CC value in another interrupt, if that's possible.



Parents Reply Children
  • I'll try it but it seems unlikely, my signal is much slower, circa 150Hz max and is an extremely clean square wave with no noise or noticeable slew (according to the oscilloscope). Besides if it were noise it wouldn't have such high period values many of which indicate 300Hz, an eternity in terms of noise.





  • Hi,

     

    snoopy20 said:
    I'll try it but it seems unlikely, my signal is much slower, circa 150Hz max and is an extremely clean square wave with no noise or noticeable slew (according to the oscilloscope). Besides if it were noise it wouldn't have such high period values many of which indicate 300Hz, an eternity in terms of noise.

    I do not have insight into the rest of your firmware, but if I assume that this is your only GPIOTE IN channel, then it might be a loading issue? Do you use a pull-up/down on the GPIO "CFG_PIN_MOTION_NUM" ?

     

    Kind regards,

    Håkon

  • Hi,

    It's an optical reader which has it's own pull-up to 3V. No issue there.

    I'm not using softdevice, NRF52DK board, no sleep modes, crystal active.

      SystemInit();
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (! NRF_CLOCK->EVENTS_HFCLKSTARTED) {}
      NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Synth << CLOCK_LFCLKSRCCOPY_SRC_Pos;
      NRF_CLOCK->TASKS_LFCLKSTART = 1;
      while (! NRF_CLOCK->EVENTS_LFCLKSTARTED) {}


    Here are some of those defines for the GPIOTE wiring.

    // motion
    #define CFG_TIMER_MOTION NRF_TIMER0
    #define CFG_TIMER_MOTION_IRQn TIMER0_IRQn
    //#define CFG_TIMER_MOTION_IRQ_HANDLER TIMER0_IRQHandler
    #define CFG_PPI_MOTION_TIMER_COMPARE 7
    #define CFG_PPI_MOTION_TIMER_OVERFLOW 8
    #define CFG_GPIOTE_CHANNEL_MOTION 5
    #define CFG_MOTION_PRESCALER 4
    #define CFG_MOTION_ONE_SECOND 1000000U // (16000000UL/(2^CFG_MOTION_PRESCALER))
    #define CFG_MOTION_SIXTY_SECONDS (CFG_MOTION_ONE_SECOND*60U)
    #define CFG_MOTION_DISC_HOLES 32U
    #define CFG_PIN_MOTION_NUM 22
    #define PIN_MOTION_CONF ((GPIO_PIN_CNF_DRIVE_S0D1     << GPIO_PIN_CNF_DRIVE_Pos) \
      | (GPIO_PIN_CNF_SENSE_High      << GPIO_PIN_CNF_SENSE_Pos) \
      | (GPIO_PIN_CNF_INPUT_Connect  << GPIO_PIN_CNF_INPUT_Pos) \
      | (GPIO_PIN_CNF_DIR_Input      << GPIO_PIN_CNF_DIR_Pos))


    I'm using Timer0 as I'm out of timers, but aware it''s usually used by SoftDevice. With softdevice not in use, it should be free? any softdevice PPI's could still be interfering?

    I use GPIOTE for 5 buttons (channels 0-4). I don't understand how another channel other than specified can make it through PPI to the timer count trigger. Are you saying that's a bug? Anyhow, the buttons aren't pressed at all during the bad counts.

  • Hi, 

    I can confirm the errata fix you referenced has fixed it, so it's also happening for much slower signals than 750KHz. 

  • Wow.  Thanks so much for writing this; I had assumed I could ignore this erratum but maybe not!

Related