Linux: Timer

Source: Internet
Author: User
Tags posix

Introduction: Use ok6410 to collect adis16405 data through imu_ev30. The collection frequency is 100Hz and a 10 ms timer is required. First, we considered a POSIX per-process timer, and found that it was okay when the load was light, and the timing was not accurate when the load was heavy. Finally, we used the PWM timer to solve the problem. To sum up.

1. a posix per-process Timer

Include <signal. h> // Signal
Include <time. h>
Include <sys/time. h>

Timer_t timer; // Timer a posix per-process timer. timer_t is actually a long type.

Struct sigevent EVP; // event, the event when the timer expires
Memset (& EVP, 0, sizeof (EVP ))
EVP. sigev_notify = sigev_thread;
Sigev_none: Do nothing. Only timeout information is queried through timer_gettime and timer_getoverrun.
Sigev_signal: when the timer expires, the kernel sends the signal specified by sigev_signo to the process.
Sigev_thread: when the timer expires, the kernel will (within this process) create a thread with sigev_notification_attributes as the thread attribute, and let it execute sigev_policy_function, and pass in sigev_value as a parameter.
EVP. sigev_policy_function = writecom; // thread function: void writecom (Union sigval V)
EVP. sigev_value.sival_int = 3; // serves as the parameter of the void writecom (Union sigval v) function.

Ret = timer_create (clock_realtime, & EVP, & timer); // create a POSIX per-process Timer
Clock_realtime: systemwide realtime clock. Real-time clock
Clock_monotonic: represents monotonic time. cannot be set.
Clock_process_cputime_id: High Resolution per-process timer.
Clock_thread_cputime_id: thread-specific timer.
Clock_realtime_hr: High Resolution version of clock_realtime.
Clock_monotonic_hr: High Resolution version of clock_monotonic
If EVP is null, a default signal is generated when the timer expires. For clock_realtimer, the default signal is sigalrm. To generate other signals except the default signal, the program must set EVP-> sigev_signo as the expected signal code. The member EVP-> sigev_notify In the struct sigevent Structure describes the actions that should be taken when the timer expires.

Struct itimerspec ts; // defines the time interval
TS. it_interval. TV _sec = 0;
TS. it_interval. TV _nsec = 10000000; // nanosecond e-9s.
TS. it_value. TV _sec = 3; // The initial timer value.
TS. it_value. TV _nsec = 0;
Ret = timer_settime (timer, timer_abstime, & TS, null); // configure and enable
If the flags value is timer_abstime, the time value specified by the value is interpreted as the absolute value (the default Interpretation Method for this value is relative to the current time ). This modified behavior can avoid obtaining the current time, calculating the relative difference between "this time" and "expected future time", and creating competition conditions during timer startup.
If the value of ovalue is not null, the previous timer expiration time will be stored in the provided itimerspec. If the timer is not started, all the members of this structure are set to 0.

2. PWM Timer

The value of the PWM Register needs to be set. The descriptions of the registers are described in detail in the initi6410 manual. Here we will focus on the implementation process. Let's take a look at the problems to be solved:
1. How to operate registers
2. How to register interrupt functions
3. The first two problems cannot be solved in the user program, so there are 3rd problems. How to Write something similar to the driver, that is, kernel module development
In fact, I don't want to learn so much at once, but there is no way for a timer to lead to so many problems.

2.1 kernel module framework

For details, see the article "Linux: compiling kernel module (from the country embedded video teaching)" (http://blog.csdn.net/leaglave_jyan/article/details/6652435)

2.2 read/write registers

Static unsigned long pwm_base_addr;
Pwm_base_addr = (unsigned long) ioremap (ox7f006000, ox44); // map the ox44 bytes starting with ox7f006000 to the memory and assign the ing address to pwm_base_addr

For example, for register tcon

Volatile unsigned int * ptcon = (volatile unsigned int *) (pwm_base_addr + ox08 );
Use * ptcon & = oxfffffff0; to operate on it

2.3 configure and enable the timer

2.3.1 Frequency Division

When the external clock is not used, the timer uses the pclk clock (the pclk frequency is displayed on the terminal when the Development Board is started)
Pclk reduces the frequency by dividing the frequency twice for the timer.
The first-level Frequency Division uses an 8-Bit Clock pre-timer for pre-division. For the timer 0 and the timer 1 share a pre-timer, the second Timer 2, 3, and 4 share, the output after the pre-division will enter the second-level divider.
The second-level divider is for each timer, and does not share the pre-division, but there are only five options for the second-level divider of each Timer: 2-, 4-, 8-, 16-, and external clock
Timer input clock frequency = pclk/(pre-timer value + 1)/(second-level frequency division value)
The values of the pre-timer 1 and pre-Timer 2 are set by the register t1_0.
The second-level division is set by the tcfg1 register.

2.3.2 timer Working Process (switched from http://blog.csdn.net/luoamforever/article/details/5483772)

1. SetTcmpbn, tcntbnTwo registers, which indicate the comparison value of timer N and the initial count value;
2. Start timer N by settingTcon, The values of tcmpbn and tcntbn are loaded.Tcmpn and tcntnIn, at the frequency of timer N, tcntn starts to reduce the count by 1, and its value can be read through the tcnton register;
3. When the value of tcntn is equal to the value of tcmpn, the output pin of timer nToutnReverse; tcntn continues to reduce the count by 1;
4. When the value of tcntn reaches 0, its output pin toutn is reversed again, andTrigger the interrupt of timer n(If the Enable is interrupted );
5. If the timer N is set"Automatic loading ",The values of tcmpbn and tcntbn registers are automatically loaded into tcmpn and tcntn to start the next counting process.

2.3.3 related Code

The timer 0 is used, and the tcon register is read to find that the timer 4 is in use
* Pt2130 | = ox7c; // The timer 0 is set to 124 pre-division.
* Ptcfg1 | = ox03; // The timer is divided into 0 and 8, and pclk/(124 + 1)/8 = 65500Hz
* Ptcntb0 = 664; // The scheduled interval is 10 ms. Note that 664 is not 665. I haven't mentioned it in many places. I always thought it was a little worse when I started to use 665, the result shows that the timer frequency is 65500/(664 + 1 ).
* Ptcon | = ox02; // start manual update
* Ptcon & = 0 xfffffffd; // disable manual update
* Ptcon | = ox09; // start automatic update
* Ptint_cstat | = 0x01; // The timer enables 0 interruptions.

2.4 interrupt processing function Registration

Ret = request_irq (irq_timer0, timer_handl, ir1__disabled, "timer_0", null );
The interrupt number of the irq_timer0 timer 0 and the timer_0 timer name.
* Irqf_disabled-keep irqs disabled when calling the Action Handler
* Irqf_sample_random-IRQ is used to feed the random Generator
* Ir1__shared-Allow sharing the IRQ among several devices
* Ir1__probe_shared-set by callers when they keep CT sharing mismatches to occur
* Irrent_timer-flag to mark this interrupt as timer interrupt
* Irqf_percpu-interrupt is per CPU
* Irqf_nobalancing-flag to exclude this interrupt from IRQ balancing
* Ir1__irqpoll-interrupt is used for polling (only the interrupt that is
* Registered first in an shared interrupt is considered
* Performance reasons)
Static irqreturn_t timer_handl (int irq, void * dev_id, struct pt_regs * regs); // Interrupt Processing Function
The Return Value of the interrupt program is a special type -- irqreturn_t. However, the interrupt program returns only two values irq_none and irq_handled.
Irq_none: After the interrupt program receives the interrupt signal, it finds that this is not the original interrupt signal specified at registration;
Irq_handled: receives an accurate interrupt signal and processes it properly.

The following macro definitions are available in irqreturn. h:
Typedef int irqreturn_t
# Define irq_none (0)
# Define IRQ _ handled (1)

Interrupt handler: the interrupt handler cannot access the user space address, and the code used to access the user space may lead to sleep, because no one guarantees that the user space page is in the memory, it may be switched out, so that access is not allowed in the critical section.

2.5 register and add a device.

# Define mytimer_major 235
Static stuct file_operations timer_fops = {
. Ower = this_module,
. IOCTL = timer_ioctl,
}; // Only one function IOCTL () is implemented here, and operations on the timer register and registration of timed interruptions are implemented in the function IOCTL (), although this is not open, however, you can call open to open the device.

Dev_t devno = mkdev (mytimer_major, 0 );
Ret = register_chrdev_region (devno, 1, "timer ");

Struct cdev;
Sruct class * pwm_class;
Cdev_init (& cdev, & timer_fops );
Cdev. Owner = this_module;
Cdev. Ops = & timer_fops;
Cdev_add (& cdev, devno, 1 );

Pwm_class = class_create (this_module;, "pwmtimerclass ");
Device_create (pwm_class, null, mkdev (mytimer_major, 0), null, "timer % d", 0 ); // here, Timer % d will appear in the/dev directory of the Development Board, that is,/dev/timer0

Opposite operation

Device_destroy (pwm_class, mkdev (mytimer_major, 0 ),);
Class_destroy (pwm_class );
Cdev_del (& cdev );
Unregister_chrdev_region (mkdev (mytimer_major, 0), 1 );

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.