Ejemplo n.º 1
0
static int stm32l4_oneshot_handler(int irq, void *context, void *arg)
{
  struct stm32l4_oneshot_s *oneshot = (struct stm32l4_oneshot_s *) arg;
  oneshot_handler_t oneshot_handler;
  FAR void *oneshot_arg;

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

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

  STM32L4_TIM_SETISR(oneshot->tch, NULL, NULL, 0);
  STM32L4_TIM_DISABLEINT(oneshot->tch, 0);
  STM32L4_TIM_SETMODE(oneshot->tch, STM32L4_TIM_MODE_DISABLED);
  STM32L4_TIM_ACKINT(oneshot->tch, 0);

  /* 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_handler(oneshot_arg);
  return OK;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
int stm32l4_oneshot_initialize(FAR struct stm32l4_oneshot_s *oneshot,
                               int chan, uint16_t resolution)
{
  uint32_t frequency;

  tmrinfo("chan=%d resolution=%d usec\n", chan, resolution);
  DEBUGASSERT(oneshot && resolution > 0);

  /* Get the TC frequency the corresponds to the requested resolution */

  frequency = USEC_PER_SEC / (uint32_t)resolution;
  oneshot->frequency = frequency;

  oneshot->tch = stm32l4_tim_init(chan);
  if (!oneshot->tch)
    {
      tmrerr("ERROR: Failed to allocate TIM%d\n", chan);
      return -EBUSY;
    }

  STM32L4_TIM_SETCLOCK(oneshot->tch, frequency);

  /* Initialize the remaining fields in the state structure. */

  oneshot->chan       = chan;
  oneshot->running    = false;
  oneshot->handler    = NULL;
  oneshot->arg        = NULL;

  /* Assign a callback handler to the oneshot */

  return stm32l4_allocate_handler(oneshot);
}
Ejemplo n.º 4
0
static ssize_t oneshot_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
{
  /* Return zero -- usually meaning end-of-file */

  tmrinfo("buflen=%ld\n", (unsigned long)buflen);
  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
  return 0;
}
Ejemplo n.º 5
0
static ssize_t oneshot_write(FAR struct file *filep, FAR const char *buffer,
                             size_t buflen)
{
  /* Return a failure */

  tmrinfo("buflen=%ld\n", (unsigned long)buflen);
  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
  return -EPERM;
}
Ejemplo n.º 6
0
int up_rtc_gettime(FAR struct timespec *tp)
{
  uint64_t secs;
  uint64_t nsecs;
  uint64_t elapsed; /* in nsec */
  irqstate_t   flags;
  uint64_t f;

  flags = spin_lock_irqsave();

  /* Get the elapsed time */

  elapsed = NSEC_PER_TICK * (uint64_t)g_system_timer;

  /* Add the tiemr fraction in nanoseconds */

  f = up_get_timer_fraction();
  elapsed += f;

  spin_unlock_irqrestore(flags);

  tmrinfo("elapsed = %lld \n", elapsed);

  /* Convert the elapsed time in seconds and nanoseconds. */

  secs  = elapsed / NSEC_PER_SEC;
  nsecs = (elapsed - secs * NSEC_PER_SEC);

  /* And return the result to the caller. */

  tp->tv_sec  = (time_t)secs;
  tp->tv_nsec = (long)nsecs;

  tmrinfo("Returning tp=(%d,%d)\n", (int)tp->tv_sec, (int)tp->tv_nsec);
  return OK;
}
Ejemplo n.º 7
0
int up_proftimerisr(int irq, uint32_t *regs, FAR void *arg)
{
  putreg32(1 << 1, rMT30STS);
  if (profile_en)
    {
      if (profile_ptr != CONFIG_PROFILE_SAMPLES)
        {
          ASSERT(current_regs);
          profile_data[profile_ptr++] = current_regs[REG_R15];
        }
      else
        {
          profile_en = 0;
          tmrinfo("PROFILING DONE\n");
        }

    }
  return 0;
}
Ejemplo n.º 8
0
static int oneshot_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
  FAR struct inode *inode;
  FAR struct oneshot_dev_s *priv;
  int ret;

  tmrinfo("cmd=%d arg=%08lx\n", cmd, (unsigned long)arg);

  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
  inode = filep->f_inode;
  priv  = (FAR struct oneshot_dev_s *)inode->i_private;
  DEBUGASSERT(priv != NULL);

  /* Get exclusive access to the device structures */

  ret = nxsem_wait(&priv->od_exclsem);
  if (ret < 0)
    {
      return ret;
    }

  /* Handle oneshot timer ioctl commands */

  switch (cmd)
    {
      /* OSIOC_MAXDELAY - Return the maximum delay that can be supported
       *                  by this timer.
       *                  Argument: A referenct to a struct timespec in
       *                  which the maximum time will be returned.
       */

      case OSIOC_MAXDELAY:
        {
          FAR struct timespec *ts = (FAR struct timespec *)((uintptr_t)arg);
          DEBUGASSERT(ts != NULL);

          ret = ONESHOT_MAX_DELAY(priv->od_lower, ts);
        }
        break;

      /* OSIOC_START - Start the oneshot timer
       *               Argument: A reference to struct oneshot_start_s
       */

      case OSIOC_START:
        {
          FAR struct oneshot_start_s *start;
          pid_t pid;

          start = (FAR struct oneshot_start_s *)((uintptr_t)arg);
          DEBUGASSERT(start != NULL);

          /* Save signalling information */

          priv->od_signo = start->signo;
          priv->od_arg   = start->arg;

          pid = start->pid;
          if (pid == 0)
            {
              pid = getpid();
            }

          priv->od_pid = pid;

          /* Start the oneshot timer */

          ret = ONESHOT_START(priv->od_lower, oneshot_callback, priv,
                              &start->ts);
        }
        break;

      /* OSIOC_CANCEL - Stop the timer
       *                Argument: A reference to a struct timespec in
       *                which the time remaining will be returned.
       */

      case OSIOC_CANCEL:
        {
          FAR struct timespec *ts = (FAR struct timespec *)((uintptr_t)arg);

          /* Cancel the oneshot timer */

          ret = ONESHOT_CANCEL(priv->od_lower, ts);
        }
        break;

      /* OSIOC_CURRENT - Get the current time
       *                 Argument: A reference to a struct timespec in
       *                 which the current time will be returned.
       */

      case OSIOC_CURRENT:
        {
          FAR struct timespec *ts = (FAR struct timespec *)((uintptr_t)arg);

          /* Get the current time */

          ret = ONESHOT_CURRENT(priv->od_lower, ts);
        }
        break;

      default:
        {
          tmrerr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg);
          ret = -ENOTTY;
        }
        break;
    }

  nxsem_post(&priv->od_exclsem);
  return ret;
}
Ejemplo n.º 9
0
static int oneshot_close(FAR struct file *filep)
{
  tmrinfo("Closing...\n");
  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
  return OK;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freerun,
                      oneshot_handler_t handler, void *arg, const struct timespec *ts)
{
  uint64_t usec;
  uint64_t regval;
  irqstate_t flags;

  tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
          handler, arg, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
  DEBUGASSERT(oneshot && handler && ts);

  /* Was the oneshot already running? */

  flags = enter_critical_section();
  if (oneshot->running)
    {
      /* Yes.. then cancel it */

      tmrinfo("Already running... cancelling\n");
      (void)sam_oneshot_cancel(oneshot, freerun, NULL);
    }

  /* Save the new handler and its argument */

  oneshot->handler = handler;
  oneshot->arg     = arg;

  /* Express the delay in microseconds */

  usec = (uint64_t)ts->tv_sec * USEC_PER_SEC + (uint64_t)(ts->tv_nsec / NSEC_PER_USEC);

  /* Get the timer counter frequency and determine the number of counts need to achieve the requested delay.
   *
   *   frequency = ticks / second
   *   ticks     = seconds * frequency
   *             = (usecs * frequency) / USEC_PER_SEC;
   */

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

  tmrinfo("usec=%llu regval=%08llx\n", usec, regval);
  DEBUGASSERT(regval <= UINT16_MAX);

  /* Set up to receive the callback when the interrupt occurs */

  (void)sam_tc_attach(oneshot->tch, sam_oneshot_handler, oneshot,
                      TC_INT_CPCS);

  /* Set RC so that an event will be triggered when TC_CV register counts
   * up to RC.
   */

  sam_tc_setregister(oneshot->tch, TC_REGC, (uint32_t)regval);

  /* Start the counter */

  sam_tc_start(oneshot->tch);

  /* The function sam_tc_start() starts the timer/counter by setting the
   * bits TC_CCR_CLKEN and TC_CCR_SWTRG in the channel control register.
   * The first one enables the timer/counter the latter performs an
   * software trigger, which starts the clock and sets the counter
   * register to zero. This reset is performed with the next valid edge
   * of the selected clock. Thus it can take up USEC_PER_TICK microseconds
   * until the counter register becomes zero.
   *
   * If the timer is canceled within this period the counter register holds
   * the counter value for the last timer/counter run. To circumvent this
   * the counter value of the freerun timer/counter is stored at each start
   * of the oneshot timer/counter.
   *
   * The function up_timer_gettime() could also be used for this but it takes
   * too long. If up_timer_gettime() is called within this function the problem
   * vanishes at least if compiled with no optimisation.
   */

  oneshot->start_count = sam_tc_getcounter(freerun->tch);

  /* Enable interrupts.  We should get the callback when the interrupt
   * occurs.
   */

  oneshot->running = true;
  leave_critical_section(flags);
  return OK;
}
Ejemplo n.º 12
0
int stm32l4_oneshot_start(FAR struct stm32l4_oneshot_s *oneshot,
                          oneshot_handler_t handler, FAR void *arg,
                          FAR const struct timespec *ts)
{
  uint64_t usec;
  uint64_t period;
  irqstate_t flags;

  tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
         handler, arg, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
  DEBUGASSERT(oneshot && handler && ts);
  DEBUGASSERT(oneshot->tch);

  /* Was the oneshot already running? */

  flags = enter_critical_section();
  if (oneshot->running)
    {
      /* Yes.. then cancel it */

      tmrinfo("Already running... cancelling\n");
      (void)stm32l4_oneshot_cancel(oneshot, NULL);
    }

  /* Save the new handler and its argument */

  oneshot->handler = handler;
  oneshot->arg     = arg;

  /* Express the delay in microseconds */

  usec = (uint64_t)ts->tv_sec * USEC_PER_SEC +
         (uint64_t)(ts->tv_nsec / NSEC_PER_USEC);

  /* Get the timer counter frequency and determine the number of counts need
   * to achieve the requested delay.
   *
   *   frequency = ticks / second
   *   ticks     = seconds * frequency
   *             = (usecs * frequency) / USEC_PER_SEC;
   */

  period = (usec * (uint64_t)oneshot->frequency) / USEC_PER_SEC;

  tmrinfo("usec=%llu period=%08llx\n", usec, period);
  DEBUGASSERT(period <= UINT32_MAX);

  /* Set up to receive the callback when the interrupt occurs */

  STM32L4_TIM_SETISR(oneshot->tch, stm32l4_oneshot_handler, oneshot, 0);

  /* Set timer period */

  oneshot->period = (uint32_t)period;
  STM32L4_TIM_SETPERIOD(oneshot->tch, (uint32_t)period);

  /* Start the counter */

  STM32L4_TIM_SETMODE(oneshot->tch, STM32L4_TIM_MODE_PULSE);

  STM32L4_TIM_ACKINT(oneshot->tch, 0);
  STM32L4_TIM_ENABLEINT(oneshot->tch, 0);

  /* Enable interrupts.  We should get the callback when the interrupt
   * occurs.
   */

  oneshot->running = true;
  leave_critical_section(flags);
  return OK;
}
Ejemplo n.º 13
0
void up_timer_initialize(void)
{
  uint32_t ticks_per_int;
  uint32_t mask_bits = 0;
  uint32_t mask_test = 0x80000000;

  lpc43_RIT_timer_stop();
  lpc43_load_RIT_timer(0);
  internal_timer = 0;

  /* Set up the IRQ here */

  irq_attach(LPC43M4_IRQ_RITIMER, lpc43_RIT_isr);

  /* Compute how many seconds per tick we have on the main clock.  If it is
   * 204MHz for example, then there should be about 4.90ns per tick
   */

  sec_per_tick = (double)1.0/(double)LPC43_CCLK;

  /* Given an RIT_TIMER_RESOLUTION, compute how many ticks it will take to
   * reach that resolution.  For example, if we wanted a 1/4uS timer
   * resolution, that would be 250ns resolution.  The timer is an integer
   * value, although maybe this should change, but that means
   * 250/1000000000*0.00000000490 = 51.02 ticks or 51 ticks, roughly.
   * We round up by 1 tick.
   */

  ticks_per_int = RIT_TIMER_RESOLUTION/(1000000000*sec_per_tick)+1;

  /* Now we need to compute the mask that will let us set up to generate an
   * interrupt every 1/4uS.  This isn't "tickless" per-se, and probably
   * should be implemented differently, however it allows me to create a
   * 64 bit nanosecond timer than can "free-run" by being updated every
   * RIT_TIMER_RESOLUTION cycles.  I would have implemented the better
   * approach, but I didn't have a good way to determine how to manage a
   * 32 bit ns timer.  Every 21 seconds the thing rolls over@ 204MHz, so
   * you'd have to set up the compare interrupt to handle the roll over.  It
   * WOULD be fewer interrupts, but it seemed to make things more
   * complicated.  When I have a better idea, I'll change this.
   */

  while (!((mask_test >> mask_bits) & ticks_per_int))
    {
      mask_bits++;
    }

  tmrinfo("mask_bits = %d, mask = %X, ticks_per_int = %d\r\n",
          mask_bits, (0xffffffff << (32 - mask_bits)), ticks_per_int);

  /* Set the mask and compare value so we get interrupts every
   * RIT_TIMER_RESOLUTION cycles.
   */

  lpc43_set_RIT_timer_mask((0xFFFFFFFF << (32 - mask_bits)));
  lpc43_load_RIT_compare(ticks_per_int);

  /* Turn on the IRQ */

  up_enable_irq(LPC43M4_IRQ_RITIMER);

  /* Start the timer */

  lpc43_RIT_timer_start();
}
Ejemplo n.º 14
0
static void sam_oneshot_handler(void *arg)
{
  tmrinfo("Expired...\n");
  sched_timer_expiration();
}
Ejemplo n.º 15
0
int stm32l4_oneshot_cancel(FAR struct stm32l4_oneshot_s *oneshot,
                           FAR struct timespec *ts)
{
  irqstate_t flags;
  uint64_t usec;
  uint64_t sec;
  uint64_t nsec;
  uint32_t count;
  uint32_t period;

  /* 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 period 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 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  = STM32L4_TIM_GETCOUNTER(oneshot->tch);
  period = oneshot->period;

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

  STM32L4_TIM_DISABLEINT(oneshot->tch, 0);
  STM32L4_TIM_SETISR(oneshot->tch, NULL, NULL, 0);
  STM32L4_TIM_SETMODE(oneshot->tch, STM32L4_TIM_MODE_DISABLED);

  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("period=%lu count=%lu\n",
             (unsigned long)period, (unsigned long)count);

      /* 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 >= period)
        {
          /* 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)(period - count)) * USEC_PER_SEC) /
                        oneshot->frequency;

          /* 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;
}
Ejemplo n.º 16
0
int sam_freerun_initialize(struct sam_freerun_s *freerun, int chan,
                           uint16_t resolution)
{
  uint32_t frequency;
  uint32_t divisor;
  uint32_t cmr;
  int ret;

  tmrinfo("chan=%d resolution=%d usec\n", chan, resolution);
  DEBUGASSERT(freerun && resolution > 0);

  /* Get the TC frequency the corresponds to the requested resolution */

  frequency = USEC_PER_SEC / (uint32_t)resolution;

  /* The pre-calculate values to use when we start the timer */

  ret = sam_tc_divisor(frequency, &divisor, &cmr);
  if (ret < 0)
    {
      tmrerr("ERROR: sam_tc_divisor failed: %d\n", ret);
      return ret;
    }

  tmrinfo("frequency=%lu, divisor=%u, cmr=%08lx\n",
          (unsigned long)frequency, (unsigned long)divisor,
          (unsigned long)cmr);

  /* Allocate the timer/counter and select its mode of operation
   *
   *   CMR_TCCLKS          - Returned by sam_tc_divisor
   *   TC_CMR_CLKI=0       - Not inverted
   *   TC_CMR_BURST_NONE   - Not gated by an external signal
   *   TC_CMR_CPCSTOP=0    - Don't stop the clock on an RC compare event
   *   TC_CMR_CPCDIS=0     - Don't disable the clock on an RC compare event
   *   TC_CMR_EEVTEDG_NONE - No external events (and, hence, no edges
   *   TC_CMR_EEVT_TIOB    - ???? REVISIT
   *   TC_CMR_ENET=0       - External event trigger disabled
   *   TC_CMR_WAVSEL_UP    - TC_CV is incremented from 0 to 0xffffffff
   *   TC_CMR_WAVE         - Waveform mode
   *   TC_CMR_ACPA_NONE    - RA compare has no effect on TIOA
   *   TC_CMR_ACPC_NONE    - RC compare has no effect on TIOA
   *   TC_CMR_AEEVT_NONE   - No external event effect on TIOA
   *   TC_CMR_ASWTRG_NONE  - No software trigger effect on TIOA
   *   TC_CMR_BCPB_NONE    - RB compare has no effect on TIOB
   *   TC_CMR_BCPC_NONE    - RC compare has no effect on TIOB
   *   TC_CMR_BEEVT_NONE   - No external event effect on TIOB
   *   TC_CMR_BSWTRG_NONE  - No software trigger effect on TIOB
   */

  cmr |= (TC_CMR_BURST_NOTGATED | TC_CMR_EEVTEDG_NONE | TC_CMR_EEVT_TIOB   |
          TC_CMR_WAVSEL_UP      | TC_CMR_WAVE         | TC_CMR_ACPA_NONE   |
          TC_CMR_ACPC_NONE      | TC_CMR_AEEVT_NONE   | TC_CMR_ASWTRG_NONE |
          TC_CMR_BCPB_NONE      | TC_CMR_BCPC_NONE    | TC_CMR_BEEVT_NONE  |
          TC_CMR_BSWTRG_NONE);

  freerun->tch = sam_tc_allocate(chan, cmr);
  if (!freerun->tch)
    {
      tmrerr("ERROR: Failed to allocate timer channel %d\n", chan);
      return -EBUSY;
    }

  /* Initialize the remaining fields in the state structure and return
   * success.
   */

  freerun->chan     = chan;
  freerun->running  = false;
  freerun->overflow = 0;

  /* Set up to receive the callback when the counter overflow occurs */

  (void)sam_tc_attach(freerun->tch, sam_freerun_handler, freerun,
                      TC_INT_COVFS);

  /* Start the counter */

  sam_tc_start(freerun->tch);
  return OK;
}
Ejemplo n.º 17
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;
}
Ejemplo n.º 18
0
int sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan,
                           uint16_t resolution)
{
  uint32_t frequency;
  uint32_t actual;
  uint32_t cmr;
  int ret;

  tmrinfo("chan=%d resolution=%d usec\n", chan, resolution);
  DEBUGASSERT(oneshot && resolution > 0);

  /* Get the TC frequency the corresponds to the requested resolution */

  frequency = USEC_PER_SEC / (uint32_t)resolution;

  /* The pre-calculate values to use when we start the timer */

  ret = sam_tc_clockselect(frequency, &cmr, &actual);
  if (ret < 0)
    {
      tmrerr("ERROR: sam_tc_clockselect failed: %d\n", ret);
      return ret;
    }

  tmrinfo("frequency=%lu, actual=%lu, cmr=%08lx\n",
          (unsigned long)frequency, (unsigned long)actual,
          (unsigned long)cmr);

  /* Allocate the timer/counter and select its mode of operation
   *
   *   TC_CMR_TCCLKS       - Returned by sam_tc_clockselect
   *   TC_CMR_CLKI=0       - Not inverted
   *   TC_CMR_BURST_NONE   - Not gated by an external signal
   *   TC_CMR_CPCSTOP=1    - Stop the clock on an RC compare event
   *   TC_CMR_CPCDIS=0     - Don't disable the clock on an RC compare event
   *   TC_CMR_EEVTEDG_NONE - No external events (and, hence, no edges
   *   TC_CMR_EEVT_TIOB    - ???? REVISIT
   *   TC_CMR_ENET=0       - External event trigger disabled
   *   TC_CMR_WAVSEL_UPRC  - TC_CV is incremented from 0 to the value of RC,
   *                         then automatically reset on a RC Compare
   *   TC_CMR_WAVE         - Waveform mode
   *   TC_CMR_ACPA_NONE    - RA compare has no effect on TIOA
   *   TC_CMR_ACPC_NONE    - RC compare has no effect on TIOA
   *   TC_CMR_AEEVT_NONE   - No external event effect on TIOA
   *   TC_CMR_ASWTRG_NONE  - No software trigger effect on TIOA
   *   TC_CMR_BCPB_NONE    - RB compare has no effect on TIOB
   *   TC_CMR_BCPC_NONE    - RC compare has no effect on TIOB
   *   TC_CMR_BEEVT_NONE   - No external event effect on TIOB
   *   TC_CMR_BSWTRG_NONE  - No software trigger effect on TIOB
   */

  cmr |= (TC_CMR_BURST_NONE  | TC_CMR_CPCSTOP     | TC_CMR_EEVTEDG_NONE  |
          TC_CMR_EEVT_TIOB   | TC_CMR_WAVSEL_UPRC | TC_CMR_WAVE          |
          TC_CMR_ACPA_NONE   | TC_CMR_ACPC_NONE   | TC_CMR_AEEVT_NONE    |
          TC_CMR_ASWTRG_NONE | TC_CMR_BCPB_NONE   | TC_CMR_BCPC_NONE     |
          TC_CMR_BEEVT_NONE  | TC_CMR_BSWTRG_NONE);

  oneshot->tch = sam_tc_allocate(chan, cmr);
  if (!oneshot->tch)
    {
      tmrerr("ERROR: Failed to allocate timer channel %d\n", chan);
      return -EBUSY;
    }

  /* Initialize the remaining fields in the state structure and return
   * success.
   */

  oneshot->chan        = chan;
  oneshot->running     = false;
  oneshot->handler     = NULL;
  oneshot->arg         = NULL;
  oneshot->start_count = 0;
  return OK;
}