int sam_oneshot_start(struct sam_oneshot_s *oneshot, oneshot_handler_t handler, void *arg, const struct timespec *ts) { uint64_t usec; uint64_t regval; irqstate_t flags; tcvdbg("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 = irqsave(); if (oneshot->running) { /* Yes.. then cancel it */ tcvdbg("Already running... cancelling\n"); (void)sam_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; */ regval = (usec * (uint64_t)sam_tc_divfreq(oneshot->tch)) / USEC_PER_SEC; tcvdbg("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); /* Enable interrupts. We should get the callback when the interrupt * occurs. */ oneshot->running = true; irqrestore(flags); return OK; }
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; }
int up_timer_cancel(FAR struct timespec *ts) { return ONESHOT_INITIALIZED(&g_tickless.oneshot) && FREERUN_INITIALIZED(&g_tickless.freerun) ? sam_oneshot_cancel(&g_tickless.oneshot, &g_tickless.freerun, ts) : -EAGAIN; }