Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: High resolution timers on AT91
PostPosted: Fri Feb 29, 2008 1:21 pm 
Offline

Joined: Sat Jun 30, 2007 1:18 am
Posts: 20
Location: Belgrade
Hi there ;)

Is there a way to use high resoultion timers (from rt preempt patch) on AT91? The best resolution I can get (2.6.23.11-rt14) is around 1ms. Is there any other way than using high res timers to get better resolution?

When I enable CONFIG_GENERIC_TIME, CONFIG_GENERIC_CLOCKEVENTS and CONFIG_HIGH_RES I'm unable to compile at91 part of kernel. (firstly, problem is in at91sam926x_time.c because sys_timer structure is changed (no offset value). When I solve that problem is that timer implementation is using timer_tick())

Code:
$ cat /proc/timer_list
Timer List Version: v0.3
HRTIMER_MAX_CLOCK_BASES: 2
now at 11995813000 nsecs

cpu: 0
clock 0:
  .index:      0
  .resolution: 999961 nsecs
  .get_time:   ktime_get_real
active timers:
clock 1:
  .index:      1
  .resolution: 999961 nsecs
  .get_time:   ktime_get
active timers:
#0: <c388de9c>, it_real_fn, S:01
# expires at 1207195374000 nsecs [in 1195199561000 nsecs]

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 14, 2008 8:14 pm 
Offline

Joined: Sun May 20, 2007 5:11 am
Posts: 23
Location: Vancouver, BC, Canada
I dont have an answer, but I am very interested. There is a patch from David Brownell that I havent tried and there is a patch I got from TimeSys which I did. Its for 2.6.22 kernels. It fails for interval < 1 ms though (at CONFIG_HZ 250, so its doing something...)


Here is a pasting of my conversation with DB:

>
> I will make this as brief as I can. We are developing a product based on the
> at91sam9260 process. We would like to use POSIX timers with better than the
> 10 or 4 ms intervals you can get if the high res timers arent available. I
> looked around hard and the only reference I can find to someone having
> implemented the necessary code is a patch you submitted,
>
> http://www.spinics.net/lists/arm-kernel/msg42268.html

Note that you'll also need a PIT clockevent conversion patch, like
the one I appended to this message, on sam9 chips.


> I can't even work out what kernel version it is patched against. Can you
> tell me
>
> - if this patch has migrated up-stream any where ?

No, and in that form it won't.


> - what versions of the kernel it is patched against ?

I don't recall. Try it and see if it applies against your
version. I suspect either 2.6.23 or 2.6.24 should work;
current GIT has some issues since the platform devices file
has changed.



> I not an expert on kernels or low level hardware - if there is any other
> info you can give me on trying to make this work for my board, it would be
> appreciated. I am happy to run test etc.
>
> Cheers and thanks
>
> Gertjan
>

========== CUT HERE
Update at91sam926x PIT to use generic time and clockevent infrastructure:

- Clocksource gives sub-microsecond timestamp precision, assuming
memory is clocked at over 16 MHz. It's less than a 32 bit counter,
unless it's is also generating IRQs.

- Clockevent device works supports periodic mode only; no oneshot
support from this hardware. No IRQs generated unless it's the
active clocksource.

Later, another timer (probably from a TC module) can provide a oneshot
clockevent device to get NO_HZ and High-Res-Timer behaior.

This also updates the timekeeping to use the actual master clock rate
on the system, instead of compile-time <asm/arch/timex.h> constants
matching what Atmel's EK boards use. (Product boards may well differ!)

Plus cleanup: rename "*_timer*" symbols to "*_pit*" (there are other
timers, but only one PIT); shorter lines; remove needless CPP stuff;
make several symbols static; etc.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
arch/arm/mach-at91/Kconfig | 8 +
arch/arm/mach-at91/at91sam926x_time.c | 169 ++++++++++++++++++++++++----------
2 files changed, 128 insertions(+), 49 deletions(-)

--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -12,15 +12,23 @@ config ARCH_AT91RM9200

config ARCH_AT91SAM9260
bool "AT91SAM9260 or AT91SAM9XE"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS

config ARCH_AT91SAM9261
bool "AT91SAM9261"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS

config ARCH_AT91SAM9263
bool "AT91SAM9263"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS

config ARCH_AT91SAM9RL
bool "AT91SAM9RL"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS

config ARCH_AT91X40
bool "AT91x40"
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-at91/at91sam926x_time.c
+ * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
*
* Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
* Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France
@@ -8,16 +8,12 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>

-#include <asm/hardware.h>
-#include <asm/io.h>
#include <asm/mach/time.h>

#include <asm/arch/at91_pit.h>
@@ -26,88 +22,163 @@
#define PIT_CPIV(x) ((x) & AT91_PIT_CPIV)
#define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20)

+static u32 pit_cycle; /* write-once */
+static u32 pit_cnt; /* access only w/system irq blocked */
+
+
/*
- * Returns number of microseconds since last timer interrupt. Note that interrupts
- * will have been disabled by do_gettimeofday()
- * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+ * Clocksource: just a monotonic counter of mck/16 cycles.
+ * We don't care whether or not PIT irqs are enabled.
*/
-static unsigned long at91sam926x_gettimeoffset(void)
+static cycle_t read_pit_clk(void)
{
- unsigned long elapsed;
- unsigned long t = at91_sys_read(AT91_PIT_PIIR);
+ unsigned long flags;
+ u32 elapsed;
+ u32 t;

- elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t); /* hardware clock cycles */
+ raw_local_irq_save(flags);
+ elapsed = pit_cnt;
+ t = at91_sys_read(AT91_PIT_PIIR);
+ raw_local_irq_restore(flags);

- return (unsigned long)(elapsed * jiffies_to_usecs(1)) / LATCH;
+ elapsed += PIT_PICNT(t) * pit_cycle;
+ elapsed += PIT_CPIV(t);
+ return elapsed;
}

+static struct clocksource pit_clk = {
+ .name = "pit",
+ .rating = 175,
+ .read = read_pit_clk,
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+
+/*
+ * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16)
+ */
+static void
+pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+{
+ unsigned long flags;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ case CLOCK_EVT_MODE_RESUME:
+ /* update clocksource counter, then enable the IRQ */
+ raw_local_irq_save(flags);
+ pit_cnt += pit_cycle * PIT_PICNT(at91_sys_read(AT91_PIT_PIVR));
+ at91_sys_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN
+ | AT91_PIT_PITIEN);
+ raw_local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ BUG();
+ /* FALLTHROUGH */
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ /* disable irq, leaving the clocksource active */
+ at91_sys_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
+ break;
+ }
+}
+
+static struct clock_event_device pit_clkevt = {
+ .name = "pit",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .rating = 100,
+ .set_mode = pit_clkevt_mode,
+};
+
+
/*
* IRQ handler for the timer.
*/
-static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
+static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
{
- volatile long nr_ticks;

- if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */
- write_seqlock(&xtime_lock);
+ /* The PIT interrupt may be disabled, and is shared */
+ if ((pit_clkevt.mode == CLOCK_EVT_MODE_PERIODIC)
+ && (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS)) {
+ unsigned nr_ticks;

- /* Get number to ticks performed before interrupt and clear PIT interrupt */
+ /* Get number of ticks performed before irq, and ack it */
nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR));
do {
- timer_tick();
+ pit_cnt += pit_cycle;
+ pit_clkevt.event_handler(&pit_clkevt);
nr_ticks--;
} while (nr_ticks);

- write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
- } else
- return IRQ_NONE; /* not handled */
+ }
+
+ return IRQ_NONE;
}

-static struct irqaction at91sam926x_timer_irq = {
- .name = "at91_tick",
- .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = at91sam926x_timer_interrupt
+static struct irqaction at91sam926x_pit_irq = {
+ .name = "pit",
+ .flags = IRQF_SHARED | IRQF_DISABLED
+ | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = at91sam926x_pit_interrupt
};

-void at91sam926x_timer_reset(void)
+static void at91sam926x_pit_reset(void)
{
- /* Disable timer */
+ /* Disable timer and irqs */
at91_sys_write(AT91_PIT_MR, 0);

- /* Clear any pending interrupts */
- (void) at91_sys_read(AT91_PIT_PIVR);
+ /* Clear any pending interrupts, wait for PIT to stop counting */
+ while (PIT_CPIV(at91_sys_read(AT91_PIT_PIVR)) != 0)
+ cpu_relax();

- /* Set Period Interval timer and enable its interrupt */
- at91_sys_write(AT91_PIT_MR, (LATCH & AT91_PIT_PIV) | AT91_PIT_PITIEN | AT91_PIT_PITEN);
+ /* Start PIT but don't enable IRQ */
+ at91_sys_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
}

/*
- * Set up timer interrupt.
+ * Set up both clocksource and clockevent support.
*/
-void __init at91sam926x_timer_init(void)
+static void __init at91sam926x_pit_init(void)
{
+ unsigned long pit_rate;
+ unsigned bits;
+
+ /* Use our actual MCK to figure out how many MCK/16 ticks per
+ * 1/HZ period (instead of a compile-time constant LATCH).
+ */
+ pit_rate = clk_get_rate(clk_get(NULL, "mck")) / 16;
+ pit_cycle = (pit_rate + HZ/2) / HZ;
+ WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0);
+
/* Initialize and enable the timer */
- at91sam926x_timer_reset();
+ at91sam926x_pit_reset();

- /* Make IRQs happen for the system timer. */
- setup_irq(AT91_ID_SYS, &at91sam926x_timer_irq);
+ /* Register clocksource. The high order bits of PIV are unused,
+ * so this isn't a 32-bit counter unless we get clockevent irqs.
+ */
+ pit_clk.mult = clocksource_hz2mult(pit_rate, pit_clk.shift);
+ bits = 12 /* PICNT */ + ilog2(pit_cycle) /* PIV */;
+ pit_clk.mask = CLOCKSOURCE_MASK(bits);
+ clocksource_register(&pit_clk);
+
+ /* Set up and register clockevents and irq handler */
+ pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
+ pit_clkevt.cpumask = cpumask_of_cpu(0);
+ setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq);
+ clockevents_register_device(&pit_clkevt);
}

-#ifdef CONFIG_PM
-static void at91sam926x_timer_suspend(void)
+static void at91sam926x_pit_suspend(void)
{
/* Disable timer */
at91_sys_write(AT91_PIT_MR, 0);
}
-#else
-#define at91sam926x_timer_suspend NULL
-#endif

struct sys_timer at91sam926x_timer = {
- .init = at91sam926x_timer_init,
- .offset = at91sam926x_gettimeoffset,
- .suspend = at91sam926x_timer_suspend,
- .resume = at91sam926x_timer_reset,
+ .init = at91sam926x_pit_init,
+ .suspend = at91sam926x_pit_suspend,
+ .resume = at91sam926x_pit_reset,
};
-


Top
 Profile  
 
 Post subject: Re: High resolution timers on AT91
PostPosted: Thu Apr 02, 2009 1:55 pm 
Offline

Joined: Wed Apr 02, 2008 9:03 am
Posts: 35
Hi,

Any news on this? I'm trying to get high resolution timers to work too.

I'm running 2.6.25.5 on at91sam9263 and I was able to configure preempt-version just by enabling the 'Preemtiple kernel' from menuconfig. I also enabled 'Hight Resolution Timer Support', but it seems that it does nothing. /proc/timer_list tells resolution of the timer is about 1ms (Kernel Hz = 1000Hz). Also the test program 'cyclictest' (http://rt.wiki.kernel.org/index.php/Cyclictest) says that there aren't high resolution timers available.

I looked from google, but all the posts I found were quite old. What's the current status of that? Is the patch still needed to get those high resolution timers to work? I'm using some patch from Atmel for the kernel, but I'm guessing it has nothing to do with those timers. If the patch is still needed, where can I find it?


Top
 Profile  
 
 Post subject: Re: High resolution timers on AT91
PostPosted: Fri Apr 03, 2009 10:30 am 
Offline

Joined: Wed Apr 02, 2008 9:03 am
Posts: 35
Okay. This thing is solved for me. I updated to kernel version 2.6.27 and then when I enabled Preemptible kernel, High resolution timer support and also Atmel AT32/AT91 Timer/Counter Library I was able to get /proc/timer_list to say that timer resolution is 1nsec. Then when I ran cyclictest with -n option the latencies stayed quite low so I'm assuming timer is working ok.


Top
 Profile  
 
 Post subject: Re: High resolution timers on AT91
PostPosted: Fri Jan 29, 2010 12:22 am 
Offline

Joined: Thu Sep 17, 2009 8:18 pm
Posts: 12
This post was helpful. I had a hard time finding the "Atmel AT32/AT91 Timer/Counter Library" option. It is ATMEL_TCLIB, and it's located at "Device Drivers"->"Misc devices"->"Atmel AT32/AT91 Timer/Counter Library.


Top
 Profile  
 
 Post subject: Re: High resolution timers on AT91
PostPosted: Thu Apr 08, 2010 4:46 pm 
Offline

Joined: Thu Mar 19, 2009 8:05 pm
Posts: 5
I'm trying to get a 200ns resolution timer to run on an AT91sam9261, which only has one timer counter block (with three timers configured). For the life of me, I can't figure out how to get it to use a timer other than the 32kHz timer.

If anyone has had success in getting this to work, I'd be very grateful for info on how you did it.

Also, I'd be interested to find out how maddis got cyclictest to compile for the arm toolchain. I ran into many compile errors that I could not figure a way around. If you have a Makefile, I'd love to see it.


Top
 Profile  
 
 Post subject: Re: High resolution timers on AT91
PostPosted: Mon Sep 27, 2010 4:47 pm 
Offline

Joined: Mon Sep 27, 2010 4:38 pm
Posts: 3
Did anybody manage to get usec precision with the hrtimers?
If so, I would be very interested to learn how...
[edit]
I already have hrtimers enabled and the resolution is 1 nsec but the precision of a hrtimer_start or hrtimer_nanosleep is miserable. I have more than 75 usecs spread!
[/edit]


Top
 Profile  
 
 Post subject: Re: High resolution timers on AT91
PostPosted: Fri Mar 18, 2011 6:48 pm 
Offline

Joined: Fri Mar 18, 2011 6:40 pm
Posts: 4
Hello,

I have tried to activate PREEMPT, HIGH_RES_TIMERS and ATMEL_TCLIB on at91sam9g20 with kernel 2.6.36, but the clock resolution is still giving me 10ms in /proc/list_timers.

Is the patch given at the beginning of this thread still needed to enable the hrtimers?
Are there any other options to activate in the kernel?

Thanks
Simon


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: