コード例 #1
0
ファイル: sam_oneshot.c プロジェクト: hll4fork/NuttX
static void sam_oneshot_handler(TC_HANDLE tch, void *arg, uint32_t sr)
{
  struct sam_oneshot_s *oneshot = (struct sam_oneshot_s *)arg;
  oneshot_handler_t oneshot_handler;
  void *oneshot_arg;

  tmrinfo("Expired...\n");
  DEBUGASSERT(oneshot && oneshot->handler);

  /* The clock was stopped, but not disabled when the RC match occurred.
   * Disable the TC now and disable any further interrupts.
   */

  sam_tc_attach(oneshot->tch, NULL, NULL, 0);
  sam_tc_stop(oneshot->tch);

  /* The timer is no longer running */

  oneshot->running = false;

  /* Forward the event, clearing out any vestiges */

  oneshot_handler      = (oneshot_handler_t)oneshot->handler;
  oneshot->handler     = NULL;
  oneshot_arg          = (void *)oneshot->arg;
  oneshot->arg         = NULL;
  oneshot->start_count = 0;

  oneshot_handler(oneshot_arg);
}
コード例 #2
0
ファイル: sam4cm_freerun.c プロジェクト: AlexShiLucky/NuttX
int sam_freerun_uninitialize(struct sam_freerun_s *freerun)
{
  DEBUGASSERT(freerun && freerun->tch);

  /* Now we can disable the timer interrupt and disable the timer. */

  sam_tc_attach(freerun->tch, NULL, NULL, 0);
  sam_tc_stop(freerun->tch);

  /* Free the timer */

  sam_tc_free(freerun->tch);
  freerun->tch = NULL;
  return OK;
}
コード例 #3
0
ファイル: sam_oneshot.c プロジェクト: hll4fork/NuttX
int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freerun,
                       struct timespec *ts)
{
  irqstate_t flags;
  uint64_t usec;
  uint64_t sec;
  uint64_t nsec;
  uint32_t count;
  uint32_t rc;

  /* Was the timer running? */

  flags = enter_critical_section();
  if (!oneshot->running)
    {
      /* No.. Just return zero timer remaining and successful cancellation.
       * This function may execute at a high rate with no timer running
       * (as when pre-emption is enabled and disabled).
       */

      ts->tv_sec  = 0;
      ts->tv_nsec = 0;
      leave_critical_section(flags);
      return OK;
    }

  /* Yes.. Get the timer counter and rc registers and stop the counter.  If
   * the counter expires while we are doing this, the counter clock will be
   * stopped, but the clock will not be disabled.
   *
   * The expected behavior is that the the counter register will freezes at
   * a value equal to the RC register when the timer expires.  The counter
   * should have values between 0 and RC in all other cased.
   *
   * REVISIT:  This does not appear to be the case.
   */

  tmrinfo("Cancelling...\n");

  count = sam_tc_getcounter(oneshot->tch);
  rc    = sam_tc_getregister(oneshot->tch, TC_REGC);

  /* In the case the timer/counter was canceled very short after its start,
   * the counter register can hold the wrong value (the value of the last
   * run). To prevent this the counter value is set to zero if not at
   * least on tick passed since the start of the timer/counter.
   */

  if (count > 0 && sam_tc_getcounter(freerun->tch) == oneshot->start_count)
    {
      count = 0;
    }

  /* Now we can disable the interrupt and stop the timer. */

  sam_tc_attach(oneshot->tch, NULL, NULL, 0);
  sam_tc_stop(oneshot->tch);

  oneshot->running = false;
  oneshot->handler = NULL;
  oneshot->arg     = NULL;
  leave_critical_section(flags);

  /* Did the caller provide us with a location to return the time
   * remaining?
   */

  if (ts)
    {
      /* Yes.. then calculate and return the time remaining on the
       * oneshot timer.
       */

      tmrinfo("rc=%lu count=%lu usec=%lu\n",
              (unsigned long)rc, (unsigned long)count, (unsigned long)usec);

      /* REVISIT: I am not certain why the timer counter value sometimes
       * exceeds RC.  Might be a bug, or perhaps the counter does not stop
       * in all cases.
       */

      if (count >= rc)
        {
          /* No time remaining (?) */

          ts->tv_sec  = 0;
          ts->tv_nsec = 0;
        }
      else
        {
          /* The total time remaining is the difference.  Convert the that
           * to units of microseconds.
           *
           *   frequency = ticks / second
           *   seconds   = ticks * frequency
           *   usecs     = (ticks * USEC_PER_SEC) / frequency;
           */

          usec        = (((uint64_t)(rc - count)) * USEC_PER_SEC) /
                        sam_tc_divfreq(oneshot->tch);

          /* Each time the timer/counter is canceled the time calculated from
           * the two registers (counter and REGC) is accurate up to an error
           * between 0 and USEC_PER_TICK microseconds. To correct this error
           * one tick which means USEC_PER_TICK microseconds are subtracted.
           */

          usec        = usec > USEC_PER_TICK ? usec - USEC_PER_TICK : 0;

          /* Return the time remaining in the correct form */

          sec         = usec / USEC_PER_SEC;
          nsec        = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;

          ts->tv_sec  = (time_t)sec;
          ts->tv_nsec = (unsigned long)nsec;
        }

      tmrinfo("remaining (%lu, %lu)\n",
              (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
    }

  return OK;
}
コード例 #4
0
int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct timespec *ts)
{
  irqstate_t flags;
  uint64_t usec;
  uint64_t sec;
  uint64_t nsec;
  uint32_t count;
  uint32_t rc;

  /* Was the timer running? */

  flags = irqsave();
  if (!oneshot->running)
    {
      /* No.. Just return zero timer remaining and successful cancellation.
       * This function may execute at a high rate with no timer running
       * (as when pre-emption is enabled and disabled).
       */

      ts->tv_sec  = 0;
      ts->tv_nsec = 0;
      irqrestore(flags);
      return OK;
    }

  /* Yes.. Get the timer counter and rc registers and stop the counter.  If
   * the counter expires while we are doing this, the counter clock will be
   * stopped, but the clock will not be disabled.
   *
   * The expected behavior is that the the counter register will freezes at
   * a value equal to the RC register when the timer expires.  The counter
   * should have values between 0 and RC in all other cased.
   *
   * REVISIT:  This does not appear to be the case.
   */

  tcvdbg("Cancelling...\n");

  count = sam_tc_getcounter(oneshot->tch);
  rc    = sam_tc_getregister(oneshot->tch, TC_REGC);

  /* Now we can disable the interrupt and stop the timer. */

  sam_tc_attach(oneshot->tch, NULL, NULL, 0);
  sam_tc_stop(oneshot->tch);

  oneshot->running = false;
  oneshot->handler = NULL;
  oneshot->arg     = NULL;
  irqrestore(flags);

  /* Did the caller provide us with a location to return the time
   * remaining?
   */

  if (ts)
    {
      /* Yes.. then calculate and return the time remaining on the
       * oneshot timer.
       */

      tcvdbg("rc=%lu count=%lu usec=%lu\n",
             (unsigned long)rc, (unsigned long)count, (unsigned long)usec);

      /* REVISIT: I am not certain why the timer counter value sometimes
       * exceeds RC.  Might be a bug, or perhaps the counter does not stop
       * in all cases.
       */

      if (count >= rc)
        {
          /* No time remaining (?) */

          ts->tv_sec  = 0;
          ts->tv_nsec = 0;
        }
      else
        {
          /* The total time remaining is the difference.  Convert the that
           * to units of microseconds.
           *
           *   frequency = ticks / second
           *   seconds   = ticks * frequency
           *   usecs     = (ticks * USEC_PER_SEC) / frequency;
           */

          usec        = (((uint64_t)(rc - count)) * USEC_PER_SEC) /
                        sam_tc_divfreq(oneshot->tch);

          /* Return the time remaining in the correct form */

          sec         = usec / USEC_PER_SEC;
          nsec        = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;

          ts->tv_sec  = (time_t)sec;
          ts->tv_nsec = (unsigned long)nsec;
        }

      tcvdbg("remaining (%lu, %lu)\n",
             (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
    }

  return OK;
}