For this topic, let's say the timer in Linux.
in the Linux kernel, there is a timer called the kernel timer, which is used to control a function, that is, the function that the timer is going to handle is executed at a certain time in the future. The handler function for kernel timer Registration is executed only once, that is, not by loop execution. if the accuracy of the delay is not high, the simplest way to implement this is as follows---Busy Waiting:
Unsigned long j = jiffies + Jit_delay * HZ; while (Jiffies < j) { ...}
The following is the meaning of the specific parameters represented:
jiffies 0
Then each time the clock interrupt handler increments the value of the variable. Number of interrupts per second , add = jiffie/hz.
jiffies purpose: Calculate elapsed time and time management
jiffies internal representation:
extern U64 jiffies_64;
extern unsigned long volatilejiffies; bit length more system about 32/64---->
|
|
+ bit: 497 days Overflow
- bit: ...
There is a concept in the timer that measures the time difference:
to determine, hz is an architecture-independent constant that can be configured as (50-1200), in x86 platform, its value is default to 1000;
The relevant header file and data structure of the timer in the kernel are as follows:
#include <linux/timer.h>/*timer*/
#include <asm/uaccess.h>/*jiffies*/
struct Timer_list {/* * All fields this change during normal runtime grouped to the * same cacheline *//timer can be used as a node of the linked list St Ruct list_head entry;//Fixed value based on jiffiesunsigned long expires;//timer internal values struct Tvec_base *base;//timer processing function void (*function) ( unsigned long); Timer processing function Parameters unsigned long data;int slack; #ifdef config_timer_statsint start_pid;void *start_site;char start_comm[16];# Endif#ifdef config_lockdepstruct lockdep_map lockdep_map; #endif};
The most basic use of the timer is to use the macros provided by the following two cores:
Initialize Timer
#define INIT_TIMER (timer) \
Init_timer_key ((timer), NULL, NULL)
Register a Timer
#define SETUP_TIMER (Timer, FN, data) \
Setup_timer_key ((timer), NULL, NULL, (FN), (data))
The following two functions are also available:
Add a Timer
void Add_timer (struct timer_list *timer)
Delete a timer
int Del_timer (struct timer_list *timer)
So what is the specific procedure for writing a timer?
1. Initialize the kernel timer
2, set the parameters of the timer execution function (optional)
3. Set timing Time
4. Set Timer function
5. Start Timer
Next, we combine a simple drive to understand the process, the drive is very simple, that is, after the 5s clock, the Development Board of the buzzer will be every 1s clock alternating.
Let's take a look at the schematic of the Development Board buzzer:
(1) Buzzer interface is located in the backplane of the circuit board, see the circuit diagram can be known to be high-level effective.
(2) corresponding to find the interface of the core board. So, our buzzer is gpd0_0.
Then find the data sheet, find the corresponding register, and then configure it.
2, check the data sheet, find the relevant registers, and configure
(1) Find Gpd0con, address is 0x114000a0, we need to configure Gpd0con (0) for the output state. That is, write the value of 0x1 to this register.
(2) Find Gpd0dat This register, used to configure the buzzer's high and low level, the physical address is 0x114000a4, just with the previous difference of 4 byte offset
We just write 1 to this register and write 0, then the buzzer can be called up, haha. Isn't it simple?
The entire simple driver code is as follows:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/ platform_device.h> #include <linux/fb.h> #include <linux/backlight.h> #include <linux/err.h># Include <linux/pwm.h> #include <linux/slab.h> #include <linux/miscdevice.h> #include <linux/ delay.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include < linux/timer.h>/*timer*/#include <asm/uaccess.h>/*jiffies*/#include <linux/delay.h>//device name # define Device_name "Bell"//device Gpio pin # define BUZZER_GPIOEXYNOS4_GPD0 (0)//define a timer list struct timer_list timer;static void Bell_ Init () {///1, request Gpio equivalent to register gpiogpio_request (buzzer_gpio,device_name);//2, call board-level driven function, configure GPIO to output state s3c_gpio_cfgpin ( Buzzer_gpio, S3c_gpio_output); 3, set the GPIO to 0, indicating low level, buzzer high level will ring Gpio_set_value (buzzer_gpio,0);} void Timer_function (unsigned Long value) {while (value) {//Set GPIO to 1, indicating high level, buzzer high level will ring Gpio_set_value (buzzer_gpio,1); PRINTK ("Buzzer On\n "); Mdelay (1000);//Set GPIO to 0, indicating low level, buzzer high level will ring Gpio_set_value (buzzer_gpio,0);p rintk (" buzzer off\n "); Mdelay (1000) ;}} static int __init tiny4412_bell_init (void) {//bell init bell_init (); Initializes the kernel timer init_timer (&timer); To perform the function of the parameter Timer.data= 1; The current jiffies value is added after 5 seconds timer.expires= jiffies + (5 * HZ); If timed out, execute this function timer.function= timer_function; Start Timer add_timer (&timer); return 0;} static void __exit tiny4412_bell_exit (void) {//Releases Gpio gpio_free (Buzzer_gpio); Delete the registered Timer Del_timer (&timer);} Module_init (Tiny4412_bell_init); Module_exit (Tiny4412_bell_exit); Module_license ("GPL"); Module_author ("Yyx"); Module_description ("Exynos4 BELL Driver");
Next, open our Development Board serial port, observe the running result:
Sure enough, the timer in the Development Board after a certain time after the start of the cycle to open and close the buzzer on our board.
Teach you to write Linux device driver---timer (one) (based on friendly arm 4412 Development Board)