示例#1
0
int sam_freerun_counter(struct sam_freerun_s *freerun, struct timespec *ts)
{
  uint64_t usec;
  uint32_t counter;
  uint32_t verify;
  uint32_t sr;
  uint32_t overflow;
  uint32_t sec;
  irqstate_t flags;

  DEBUGASSERT(freerun && freerun->tch && ts);

  /* Temporarily disable the overflow counter.  NOTE that we have to be careful
   * here because  sam_tc_getpending() will reset the pending interrupt status.
   * If we do not handle the overflow here then, it will be lost.
   */

  flags    = enter_critical_section();
  overflow = freerun->overflow;
  counter  = sam_tc_getcounter(freerun->tch);
  sr       = sam_tc_getpending(freerun->tch);
  verify   = sam_tc_getcounter(freerun->tch);

  /* If an interrupt was pending before we re-enabled interrupts,
   * then the overflow needs to be incremented.
   */

  if ((sr & TC_INT_COVFS) != 0)
    {
      /* Increment the overflow count and use the value of the
       * guaranteed to be AFTER the overflow occurred.
       */

      overflow++;
      counter = verify;

      /* Update freerun overflow counter. */

      freerun->overflow = overflow;
    }

  leave_critical_section(flags);

  tmrinfo("counter=%lu (%lu) overflow=%lu, sr=%08lx\n",
          (unsigned long)counter,  (unsigned long)verify,
          (unsigned long)overflow, (unsigned long)sr);

  /* Convert the whole thing to units of microseconds.
   *
   *   frequency = ticks / second
   *   seconds   = ticks * frequency
   *   usecs     = (ticks * USEC_PER_SEC) / frequency;
   */

  usec = ((((uint64_t)overflow << 16) + (uint64_t)counter) * USEC_PER_SEC) /
         sam_tc_divfreq(freerun->tch);

  /* And return the value of the timer */

  sec         = (uint32_t)(usec / USEC_PER_SEC);
  ts->tv_sec  = sec;
  ts->tv_nsec = (usec - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;

  tmrinfo("usec=%llu ts=(%lu, %lu)\n",
          usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);

  return OK;
}
int sam_freerun_counter(struct sam_freerun_s *freerun, struct timespec *ts)
{
  uint64_t usec;
  uint32_t counter;
  uint32_t verify;
  uint32_t sr;
  uint32_t overflow;
  uint32_t sec;
  irqstate_t flags;

  DEBUGASSERT(freerun && freerun->tch && ts);

  /* Temporarily disable the overflow counter */

  flags    = irqsave();
  overflow = freerun->overflow;
  counter  = sam_tc_getcounter(freerun->tch);
  sr       = sam_tc_getpending(freerun->tch);
  verify   = sam_tc_getcounter(freerun->tch);
  irqrestore(flags);

  tcvdbg("counter=%lu (%lu) overflow=%lu, sr=%08lx\n",
         (unsigned long)counter,  (unsigned long)verify,
         (unsigned long)overflow, (unsigned long)sr);

  /* If an interrupt was pending before we re-enabled interrupts,
   * then our value of overflow needs to be incremented.
   */

  if ((sr & TC_INT_COVFS) != 0)
    {
      /* Increment the overflow count and use the value of the
       * guaranteed to be AFTER the overflow occurred.
       */

      overflow++;
      counter = verify;

      tcvdbg("counter=%lu overflow=%lu\n",
             (unsigned long)counter, (unsigned long)overflow);
    }

  /* Convert the whole thing to units of microseconds.
   *
   *   frequency = ticks / second
   *   seconds   = ticks * frequency
   *   usecs     = (ticks * USEC_PER_SEC) / frequency;
   */

  usec = ((((uint64_t)overflow << 32) + (uint64_t)counter) * USEC_PER_SEC) /
         sam_tc_divfreq(freerun->tch);

  /* And return the value of the timer */

  sec         = (uint32_t)(usec / USEC_PER_SEC);
  ts->tv_sec  = sec;
  ts->tv_nsec = (usec - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;

  tcvdbg("usec=%llu ts=(%lu, %lu)\n",
          usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);

  return OK;
}