I implement a driver for HW timers.
Yet, it seems that there is already interface for HW timers, so I am not sure that such driver is actually needed. I see the following in kernel and in userspace:
hrtimer in kernel:
int hrtimer_start(struct hrtimer *timer, ktime_t time,
enum hrtimer_mode mode);
timer_create() in userspace:
int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
Yet, I don't see in these APIs any mention of the actual HW timer number.
So , which HW timer number is actually used on calling these APIs ?
For example, on call to timer_create(), which HW timer is used ?
the timer_create() syscall internally uses hrtimer (hrtimer is a high res timer).
In MACHINE_START() macro of your board file we pass a timer, which will be used for clock events and this clock is used by hrtimer.
also refer http://elinux.org/High_Resolution_Timers this should provide more info.
Related
I'm sure there's a good reason for this, but I can't see what it is. Inside __handle_irq_event_percpu the kernel loops over all the handlers registered for a particular IRQ line and calls it. What I don't understand is why this loop isn't exited when the first handler returning IRQ_HANDLED is reached? It seems like a simple performance improvement, so there must be something I don't understand.
Does anyone know why?
In the Linux source tree, __handle_irq_event_percpu() is in kernel/irq/handle.c:
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
irqreturn_t retval = IRQ_NONE;
unsigned int irq = desc->irq_data.irq;
struct irqaction *action;
record_irq_time(desc);
for_each_action_of_desc(desc, action) {
irqreturn_t res;
trace_irq_handler_entry(irq, action);
res = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, res);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pS enabled interrupts\n",
irq, action->handler))
local_irq_disable();
switch (res) {
case IRQ_WAKE_THREAD:
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
__irq_wake_thread(desc, action);
/* Fall through - to add to randomness */
case IRQ_HANDLED:
*flags |= action->flags;
break;
default:
break;
}
retval |= res;
}
return retval;
}
The for_each_action_of_desc(desc, action) macro travels in the action list of the IRQ descriptor:
#define for_each_action_of_desc(desc, act) \
for (act = desc->action; act; act = act->next)
[...]
struct irq_desc {
struct irq_common_data irq_common_data;
struct irq_data irq_data;
unsigned int __percpu *kstat_irqs;
irq_flow_handler_t handle_irq;
struct irqaction *action; /* IRQ action list */
[...]
struct irqaction {
irq_handler_t handler;
void *dev_id;
void __percpu *percpu_dev_id;
struct irqaction *next;
irq_handler_t thread_fn;
struct task_struct *thread;
struct irqaction *secondary;
unsigned int irq;
unsigned int flags;
unsigned long thread_flags;
unsigned long thread_mask;
const char *name;
struct proc_dir_entry *dir;
} ____cacheline_internodealigned_in_smp;
There are multiple entries in the action list if the interrupt line is shared by several devices. So, several devices may enter in interrupt state at the same time. Hence, the action is to be called for all the devices sharing the line to check if there is something to do.
N.B.:
This answer is better argumented on the subject
This blog article depicts the steps of interrupt handling in the Linux kernel.
Inside __handle_irq_event_percpu the kernel loops over all the handlers registered for a particular IRQ line and calls it. What I don't understand is why this loop isn't exited when the first handler returning IRQ_HANDLED is reached? It seems like a simple performance improvement, so there must be something I don't understand.
There are 2 cases to consider - shared edge triggered IRQs and shared level triggered IRQs.
Shared Edge Triggered IRQs
In this case, 2 or more devices can send an IRQ at the same time or at similar times. If this happens and the "for each driver" loop is exited when the first handler returns IRQ_HANDLED then other devices can/will become stuck in a "waiting for IRQ handler's attention" state (most likely causing devices to lock up permanently). To avoid that, for edge triggered IRQs, the kernel's "for each driver" loop must notify all drivers (and can't stop as soon as one returns IRQ_HANDLED).
Note that shared edge triggered IRQs are rare. For 80x86 PCs it's possible when there are more than 2 serial port controllers (which can be solved by using the same driver for all serial port controllers and dealing with the problem in the driver and not in the kernel's IRQ management code), but apart from that shared edge triggered IRQs simply don't exist (on 80x86 PCs).
Shared Level Triggered IRQs
In this case, 2 or more devices can send an IRQ at the same time or at similar times; but if this happens and the "for each driver" loop is exited when the first handler returning IRQ_HANDLED then the other IRQs (from other devices) are not lost. Instead, the interrupt controller will see "level is still being triggered by at least one device" and will re-issue the IRQ (and keep sending more IRQs until all devices are satisfied).
For shared level triggered IRQs, it's a performance compromise (that has nothing to do with "correctness"). More specifically:
If it's very likely that multiple devices will want attention at the same or similar time; then you can improve performance by continuing the loop (when a driver returns IRQ_HANDLED) because it's likely that this will avoid the cost of the interrupt controller re-issuing the IRQ.
If it's very unlikely that multiple devices will want attention at the same or similar time; then you can improve performance by stopping the loop as soon as driver returns IRQ_HANDLED because it's likely that this will avoid the cost of the executing unnecessary device drivers' interrupt handlers.
Note that this depends on the order that device drivers' IRQ handlers are called. To understand this imagine there are 2 devices sharing an IRQ line and almost all IRQs come from the first device. If the first device's driver's IRQ handler is called first and returns IRQ_HANDLED then it'd be unlikely that the second device also sent an IRQ at the same time; but if the second device's driver's IRQ handler is called first and returns IRQ_HANDLED then it'd be likely that the second device also sent an IRQ at the same time.
In other words; if the kernel sorted the list of device drivers in order of "chance the device sent an IRQ"; then it becomes more likely that stopping the loop as soon as a driver returns IRQ_HANDLED will improve performance (and it becomes more likely that the first driver called will return IRQ_HANDLED sooner).
However tracking statistics and "being smarter" (determining how to optimize performance dynamically based on those statistics) would also add a little overhead, and (at least in theory, especially if device drivers' interrupt handlers are extremely fast anyway) this could cost more performance than you'd gain.
Essentially; it'd take a lot of work (research, benchmarking) to quantify and maximize the potential benefits; and it's a lot easier to not bother (and always call all device driver's interrupt handlers" even when it is worse).
While creating FreeRTOS application project with STM32CubeMx, there are two ways you can use to introduce delay, namely osDelay and HAL_Delay.
What's the difference among them and which one should be preferred?
osDelay Code:
/*********************** Generic Wait Functions *******************************/
/**
* #brief Wait for Timeout (Time Delay)
* #param millisec time delay value
* #retval status code that indicates the execution status of the function.
*/
osStatus osDelay (uint32_t millisec)
{
#if INCLUDE_vTaskDelay
TickType_t ticks = millisec / portTICK_PERIOD_MS;
vTaskDelay(ticks ? ticks : 1); /* Minimum delay = 1 tick */
return osOK;
#else
(void) millisec;
return osErrorResource;
#endif
}
HAL_Delay Code:
/**
* #brief This function provides accurate delay (in milliseconds) based
* on variable incremented.
* #note In the default implementation , SysTick timer is the source of time base.
* It is used to generate interrupts at regular time intervals where uwTick
* is incremented.
* #note ThiS function is declared as __weak to be overwritten in case of other
* implementations in user file.
* #param Delay: specifies the delay time length, in milliseconds.
* #retval None
*/
__weak void HAL_Delay(__IO uint32_t Delay)
{
uint32_t tickstart = 0;
tickstart = HAL_GetTick();
while((HAL_GetTick() - tickstart) < Delay)
{
}
}
HAL_Delay is NOT a FreeRTOS function and _osDelay is a function built around FreeRTOS function. (acc #Clifford: ) They both are entirely different functions by different developers for different purposes.
osDelay is part of the CMSIS Library and uses vTaskDelay() internally to introduce delay with the difference that input argument of osDelay is delay time in milliseconds while the input argument of _vTaskDelay() is number of Ticks to be delayed. (acc. #Bence Kaulics:) Using this function, OS will be notified about the delay and OS will change the status of task to blocked for that particular time period.
HAL_Delay is part of the hardware abstraction layer for our processor. It basically uses polling to introduce delay. (acc. #Bence Kaulics:) Using this function, OS won't be notified about the delay. Also if you do not use OS, then HAL_Delay is the default and only blocking delay to use provided by the HAL library. (acc. #Clifford: ) This is part of HAL Library and can be used without FreeRTOS (or when FreeRTOS is not running)
To introduce Delay using FreeRTOS functions, you can use vTaskDelay() or vTaskDelayUntil() after the scheduler has started.
(acc. #Clifford: )
Always Favour FreeRTOS API function if you want your application to be deterministic.
CubeMX is a collection of parts from multiple sources.
It does not look like HAL_Delay() is intended for use with an RTOS because it is a NULL loop delay. If you call HAL_Delay() from an RTOS task then the task will continue to run until the delay has expired. Higher priority tasks will be able to run, but lower priority tasks will be starved of any processing time during the delay period. That is a waste of processing time, power, and can be detrimental to system responsiveness.
osDelay() on the other hand effects a delay using the RTOS. It tells the RTOS that it has nothing to do until the delay period has expired, so the RTOS does not assign any processing time to the task during that period. That saves processing time, potentially saves power, and allows lower priority tasks to get processing time during the delay period. http://www.freertos.org/FAQWhat.html#WhyUseRTOS
There is a task with the highest priority. If you are going to use the HAL_Delay to block the task then probably there won't be a context switch because the scheduler won't be notified that the task currently just polls a tick counter in a while loop and actually does not do any useful operation. Tasks with lower priority won't run.
The other function uses the vTaskDelay function of the OS, I did not peek into its source code, but probably this will notify the OS the current task wants to be blocked for a certain time, so the task's state will change to blocked and the scheduler can switch to a lower prio task in the meanwhile.
HAL_Delay is used across the stm32_HAL library, including in some case, the function being called in ISR. Beside the naming implication that it is hardware abstract layer, the timer that used the HAL_Delay (HAL_GetTick) needs to have highest NVIC priority. (because it may be called inside ISR and can't be blocked) Whether this is good or bad from the implementation point of view, there are some discussions in web. However, this is the way ST do, you choose if you want to use STM32_HAL.
osDelay is in CMSIS layer is implemented with vTaskDelay. Which use the systick function as timer. The FreeRTOS also use systick to do task context switch. According to FreeRTOS document. The NVIC priority of systick need to be lowest. (So it won't get into the middle of ISR).
Which function is preferred depend on what you are doing, one has highest priority and the one has lowest (according to ST and FreeRTOS recommendation). That's the reason that if you use STM32CubeMX, it will ask you to assign a hardware timer as the 'tick' in addition to systick if you choose to use FreeRTOS.
The answer is quite simple,
If your project is bare-metal (means without os), you should(or can) use HAL_Delay.
The "weak" symbol implementation uses a code like the below.
You can declare your own function if you want.
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a period to guaranty minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
while((HAL_GetTick() - tickstart) < wait)
{
}
}
But if your project has an os (lets say FreeRTOS or Keil-RTX) or any other, then you should use a osDelay. This is because as #ARK4579 explained if you use hal_delay with the above function definition then the above function is a blocking call, which means this is just consuming cycles. With osDelay, the caller task will go into blocked state and when the ticks are completed, the task will be in Ready state once again. So here you don't consume any cycles. It is a non-blocking call.
I'd like to write an open-sourced core driver for controlling stepper motors in Linux. In this case, especially for 3D-Printers.
The basic idea is that the driver reserves pins on one IO port, and then manipulates those pins at once. It receives a buffer full of "toggle this, toggle that" values, and then emits those to the port, using a hardware timer.
Now the question is: Is there any way to handle a specific hardware interrupt as fast as possible?
The chip in question is an Allwinner H3, and I am using the TMR1 resource of said chip (IRQ 51). I can use it just fine, and it works as an interrupt as well:
static irqreturn_t stepCore_timer_interrupt(int irq, void *dev_id)
{
writel(TMR1_IRQ_PEND, TMR_IRQ_ST_VREG);
icnt++;
porta_state = readl(PA_VDAT);
porta_state &= porta_mask;
if(icnt & 0x00000001)
{
porta_state |= 0x00000001;
}
writel(porta_state, PA_VDAT);
return IRQ_HANDLED;
}
static struct irqaction stepCore_timer_irq = {
.name = "stepCore_timer",
.flags = IRQF_DISABLED | IRQF_NOBALANCING , IRQF_PERCPU,
.handler = stepCore_timer_interrupt,
.dev_id = NULL,
};
static void stepCore_timer_interrupt_setup(void)
{
int ret;
u32 val;
writel( 24000000, TMR1_INTV_VALUE_VREG );
writel( ( TMR1_MODE_CONTINUOUS | TMR1_CLK_PRES_1 | TMR1_CLK_SRC_OSC24M ), TMR1_CTRL_VREG );
ret = setup_irq(SUNXI_IRQ_TIMER1, &stepCore_timer_irq);
if (ret)
printk("%s: ERROR: failed to install irq %d\n", __func__, SUNXI_IRQ_TIMER1);
else
printk("%s: irq %d installed\n", __func__, SUNXI_IRQ_TIMER1);
ret = irq_set_affinity_hint(SUNXI_IRQ_TIMER1, cpumask_of(3));
if (ret)
printk("%s: ERROR: failed to set irq affinity for irq %d\n", __func__, SUNXI_IRQ_TIMER1);
else
printk("%s: set irq affinity for irq %d\n", __func__, SUNXI_IRQ_TIMER1);
/* Enable timer0 interrupt */
val = readl(TMR_IRQ_EN_VREG);
writel(val | TMR1_IRQ_EN, TMR_IRQ_EN_VREG);
}
TMR1 is otherwise unused (in fact, I had to add it myself) and so far works. However, there is quite some latency in handling the rather simple IRQ routine. Since I want to produce some code that is usable for a 3D printer, I very much like a more "stable" timer interrupt.
So, my question is: Is there any way to have a very short IRQ routine in Linux that has the highest possible priority? Or even doesn't care about the Linux scheduler at all, and just "does it's thing"? Basically a raw IRQ handler, ignoring what Linux thinks it should be?
The core it runs on is dedicated to just that task, anyways. The handler will be as short as possible: fetch an u32 from an array, write that to the port, done.
Preferably I would like to have something that just ignores the remainder of Linux all together. Yes, I know that that isn't the way to do it. But this is meant for a rather special case, so I have no qualms with adapting the regular kernel sources to suit those needs.
Oh, that reminds me, the kernel is 3.4.112 with the suitable preempt-rt patches.
Any help is greatly appreciated.
Greetings,
Chris
Here is a general solution to this issue. You can write a kernel module which will overwrite the existing interrupt handling routine and will be replaced by your own routine, where you can handle your irq of interest and redirect all the irq to the existing kernel interrupt handling routine. It's possible for x86 arch where you will get low level CPU instructions to get the existing address of interrupt description routine (lidt). I believe it should be possible for ARM too. Now, Linux has technique of CPU isolation isolcpus by utilizing this technique you can take a CPU out of scheduler domain i.e. no task will be scheduled on that particular CPU, until you specify a task to be run on that particular CPU (using taskset). After you take a CPU out of scheduler domain you can take help of the technique of affine a interrupt to that isolated CPU, you can do it via /proc/irq/IRQ_NUMBER/smp_affinity. Now all of your interrupt will be handled by this isolated CPU and 100% dedicated to that interrupt. And with your own IRQ routine you have full control over the interrupt handling.
Hopefully this will help!
Have you thought about using FIQ for that. We have a blog post about it:
http://free-electrons.com/blog/fiq-handlers-in-the-arm-linux-kernel/
I am trying to disable interrupts through C code but stuck at request_irq(). One argument to request_irq() is flag and SA_INTERRUPT flag is now deprecated. Can anyone tell me alternative to SA_INTERRUPT?. I am using kernel version 3.8.
Any other alternative to request_irq() for disabling interrupts?
request_irq() does not "disable" an interrupt. It is called by a driver that wants to attach an interrupt service routine to an IRQ. The flag is IRQF_SHARED if the interrupt is shared or 0 otherwise.
Here is an example from a driver for Realtek 8169 PCIe network adapter: http://lxr.free-electrons.com/source/drivers/net/ethernet/realtek/r8169.c
retval = request_irq(pdev->irq, rtl8169_interrupt,
(tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
dev->name, dev);
In the example above, rtl8169_interrupt is the interrupt service routine (ISR) that will be invoked each time an IRQ is raised.
It is the job of the ISR to find out if the interrupt was indeed fired by the "owned" device (relevant for shared interrupts) then if the device indeed fired the interrupt, the ISR reads interrupt status then clears the interrupt.
I want to write a task that does some polling on some IOs. Now, I need it to not block the cpu but to check the IOs every 1 microsecond or so.
I'm a relative VxWorks newbie and just realized that inserting a usleep(1); into my polling loop probably won't do what I need it to do. How do I best go about this?
I have figured out that sysClkRateGet() returns 60 which isn't good enough for me. I need to poll and react fast but can't block the other things that are going on in the CPU, so I guess taskDelay() won't do it for me... is there anything else that allows for a shorter downtime of my task (than 1/60 seconds)?
edit
I think I've figured out that it's much smarter to have a timer kicking in every 1us that executes my short polling function.
i triggered the timer like this:
timer_t polltimerID;
struct itimerspec poll_time;
poll_time.it_value.tv_sec = 0;
poll_time.it_value.tv_nsec= 1000;
poll_time.it_interval.tv_sec = 0;
poll_time.it_interval.tv_nsec= 1000; // execute it every 1us
if(timer_create (CLOCK_REALTIME, NULL, &polltimerID))
printf("problem in timer_create(): %s",strerror(errno));
if(timer_connect (polltimerID,MyPollFunction,0))
printf("problem in timer_connect(): %s",strerror(errno));
if(timer_settime (polltimerID, 0, &poll_time, NULL))
printf("problem in timer_settime(): %s",strerror(errno));
But I'm not exactly sure yet, what the priority of the timer is and if (and how) it is able to preempt a current task, anyone?
The posix timer won't do what you want as it's driven off the system clock (which as you pointed out is at 60Hz).
There is no "built-in" OS function that will give you a 100KHz timer.
You will have to find some unused hardware timer on your board (CPU reference manual is useful)
You will have to configure the timer registers for you 100KHz (again Ref. Manual is good)
You will have to hook up the timer interrupt line to your function: intConnect (vector, fn, arg)
The VxWorks Kernel programmers manual has information about writing Interrupt Service Routines.