Mini2440 button driver adds timer to eliminate jitter

Publisher:数据之翼Latest update time:2022-10-13 Source: csdnKeywords:mini2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The test program and Makefile are the same as the previous experiment. Here we only need to record the source code of the driver. The changes are not big. We just move the operations of waking up the process and sending asynchronous signals to the timeout function of the timer. This is done The purpose is to eliminate the mechanical jitter of the keys.


Driver source code:


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#define GRH_MODULE_NAME "key_interrupt"

 

static int major;

static struct class *key_interrupt_class;

static struct class_device *key_interrupt_device; 

static int key_value;

 

//Two variables required by the wait_event_interruptible function

static DECLARE_WAIT_QUEUE_HEAD(grh_wait_interrupt); //Sleeping process queue head

static volatile int sleep_for_interrupt; //When this variable is 0, the read function will sleep, set it to 1 in the interrupt, and set it to 0 at the end of the read function

 

//Asynchronous signal queue definition

static struct fasync_struct *grh_async_queue;

 

//Define a timer for key anti-shake

static struct timer_list grh_timer_shake;

static int first_timer_timeout;

 

//pin_desc is a description of each key interrupt. It can not only be an integer, but also a more complex field. Here, a simple key value will suffice.

int pin_desc[6] = {

1, 2, 3, 4, 5, 6

};

 

 

//interrupt handler function

static irqreturn_t grh_handle_key_eint(int irq, void *dev_id){

int *p;

p = dev_id;

 

//printk(KERN_EMERG"key pressed! key=%dn", *p);

key_value = *p;

 

//Reset the timeout time of the timer, where HZ is the system count value corresponding to one second. The following timer is 100ms.

mod_timer(&grh_timer_shake, jiffies+HZ/10);

 

 

//The work of waking up the dormant process and sending asynchronous signals is left to the timer timeout processing function.

 

return IRQ_HANDLED;

}

 

static void grh_timer_shake_handler(unsigned long n){

if(first_timer_timeout){

first_timer_timeout = 0;

return;

}

 

//Wake up the dormant process

sleep_for_interrupt = 1;

wake_up_interruptible(&grh_wait_interrupt);

 

//Send asynchronous signal to user space process

kill_fasync(&grh_async_queue, SIGIO, POLL_IN);

}

 

 

static void init_key(void){

//Register the irq interrupt processing function, bind the key value and interrupt number, and hand over all operations of clearing interrupts and initializing interrupt-related registers

//The kernel completes it automatically. There is no need to explicitly read and write registers like a bare-metal program. After an interrupt occurs, it will automatically jump to grh_handle_key_eint.

request_irq(IRQ_EINT8, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key1", pin_desc);

request_irq(IRQ_EINT11, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key2", pin_desc+1);

request_irq(IRQ_EINT13, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key3", pin_desc+2);

request_irq(IRQ_EINT14, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key4", pin_desc+3);

request_irq(IRQ_EINT15, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key5", pin_desc+4);

request_irq(IRQ_EINT19, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key6", pin_desc+5);

}

 

static int key_interrupt_open(struct inode *inode, struct file *file){

printk(KERN_EMERG"DRIVER: OPENn");

sleep_for_interrupt = 0;

init_key();

return 0;

}

 

static ssize_t key_interrupt_write(struct inode *inode, const char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: WRITEn");

return 0;

}

 

static ssize_t key_interrupt_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: READn");

//Determine whether to add the driver process to the sleep queue grh_wait_interrupt based on the value of sleep_for_interrupt, and sleep the process immediately

wait_event_interruptible(grh_wait_interrupt, sleep_for_interrupt);

copy_to_user(buf, &key_value, 4);

 

//The next time you enter read, continue to sleep and wait for an interrupt to occur.

sleep_for_interrupt = 0;

return 0;

}

 

int key_interrupt_release(struct inode *inode, struct file *file){

//Logout interrupt

free_irq(IRQ_EINT8, pin_desc);

free_irq(IRQ_EINT11, pin_desc+1);

free_irq(IRQ_EINT13, pin_desc+2);

free_irq(IRQ_EINT14, pin_desc+3);

free_irq(IRQ_EINT15, pin_desc+4);

free_irq(IRQ_EINT19, pin_desc+5);

printk(KERN_EMERG"DRIVER: RELEASEn");

return 0;

}

 

//sys_poll will repeatedly call key_interrupt_poll in an infinite loop

static unsigned int key_interrupt_poll(struct file *file, struct poll_table_struct *wait){

unsigned int mask;

printk(KERN_EMERG"DRIVER POLLn");

poll_wait(file, &grh_wait_interrupt, wait); //Put the current process into the sleep queue, but do not sleep immediately

mask = 0;

if(sleep_for_interrupt){ //Interrupt occurred

mask |= POLLIN | POLLRDNORM; //Set the flag bit with readable data to 1, and the user layer can get this mask

}

 

return mask;

/*

If the returned mask is 0, then the process directly enters scheduled sleep. If an interrupt occurs during scheduled sleep, the value in sys_poll

After the scheduled sleep ends, sys_poll will call key_interrupt_poll in a loop again, but at this time the mask must return a non-zero value.

The hibernation in sys_poll ends and the process continues running. If the interrupt never occurs during scheduled sleep, then after the scheduled sleep times out,

sys_poll calls key_interrupt_poll again, and then determines whether it times out. If it times out, it directly ends the sleep of the process. This is

The general principle of the poll mechanism of the Linux kernel. In this way, when the poll function is called once at the user level, the maximum sleep time of the process is the wait parameter passed in.

As soon as the interrupt occurs, the scheduled sleep will end immediately, otherwise the process will sleep until the end of a scheduled sleep.

*/

}

 

//When the user space program calls fcntl(fd, F_SETFL, flag | FASYNC), the following asynchronous notification setting function will be called

static int key_interrupt_fasync(int fd, struct file *file, int on){

//fasync_helper function will pass the pid of the user space process into grh_async_queue

//In this way, the signal sent in the interrupt handling function can be received by the user space application

printk(KERN_EMERG"DRIVER : FASYNCn");

 

//The work of initializing grh_async_queue is left to fasync_helper, and the driver will not implement it.

return fasync_helper(fd, file, on, &grh_async_queue); 

}

 

static struct file_operations key_interrupt_fops = {

.owner = THIS_MODULE,

.open = key_interrupt_open,

.write = key_interrupt_write,

.read = key_interrupt_read,

.release = key_interrupt_release,

.poll = key_interrupt_poll,

.fasync = key_interrupt_fasync,

};

 

int key_interrupt_module_init(void){

printk(KERN_EMERG"INIT MODULE!n");

 

//Initialize the anti-shake timer, the default timeout is 0

init_timer(&grh_timer_shake);

grh_timer_shake.function = grh_timer_shake_handler;

add_timer(&grh_timer_shake);

first_timer_timeout = 1;

 

//register the driver with the device

major = register_chrdev(0, GRH_MODULE_NAME, &key_interrupt_fops);

 

//create my own device class

key_interrupt_class = class_create(THIS_MODULE, "key_interrupt_class");

//create my device of my own class

key_interrupt_device = device_create(key_interrupt_class, NULL, MKDEV(major,0), NULL, "key_interrupt_device");

 

return 0;

}

 

void key_interrupt_module_exit(void){

unregister_chrdev(major, GRH_MODULE_NAME);

device_unregister(key_interrupt_device);

class_destroy(key_interrupt_class);

printk(KERN_EMERG"EXIT MODULE!n");

}

 

module_init(key_interrupt_module_init);

module_exit(key_interrupt_module_exit);

 

MODULE_AUTHOR("GRH");

MODULE_VERSION("1.0");

MODULE_DESCRIPTION("KEY POLL DRIVER");

MODULE_LICENSE("GPL");


Keywords:mini2440 Reference address:Mini2440 button driver adds timer to eliminate jitter

Previous article:mini2440 button-driven POLL mechanism experiment
Next article:mini2440 button driver asynchronous signal notification mode experiment

Recommended ReadingLatest update time:2024-11-16 04:12

PIC32MZ tutorial -- Watchdog Timer
  Watchdog is a very necessary module for embedded system. Someone said that embedded system operates without watchdog enabled just like the car without air bag. You should always enabled watchdog as possible as you can.    The PIC32MZ Watchdog Timer (WDT), when enabled, operates from the internal Low-Power RC (LPRC
[Microcontroller]
Let's learn mini2440 bare metal development (XI) -- mini2440 timer 0 interrupt experiment
When explaining the system clock and timer earlier, an experiment was given. The function implemented was: using the function of timer 0 to make the LED flash once per second. At that time, it was implemented using the query method, and now the interrupt method is used to implement the above function. The following
[Microcontroller]
Let's learn mini2440 bare metal development (XI) -- mini2440 timer 0 interrupt experiment
How to make embedded Linux kernel
The method of making a Linux kernel for an embedded platform is basically the same as that of making a Linux kernel for a PC (x86) platform. The following describes how to make a kernel for the mini2440 development board. 1. Clear the original configuration and intermediate files (execute the command in the Linux kern
[Microcontroller]
【STM8L】STM8L timer2 generates PWM
1. Introduction This article introduces how to use timer2 in the STM8L series to generate 38K frequency PWM. Among them, this article uses the first channel (PB0) of timer2. 2. Experimental Platform Compiler software: IAR for STM8 1.42.2 Hardware platform: stm8l101f3p6 development board Emulator: ST-LINK
[Microcontroller]
【STM8L】STM8L timer2 generates PWM
Mini2440 Linux Memory Layout
In the process of learning Linux memory addressing, I noticed that on the x86 architecture, segmentation and paging mechanisms coexist. However, under the RSIC architecture, only paging is generally supported. "In-depth Understanding of the Linux Kernel" introduces the Linux physical memory layout on the x86 archite
[Microcontroller]
mini2440 uses J-LINK to download directly to NOR-FLASH
Configuration of J-Flash ARM. Generally speaking, you will find some *.jflash configuration files in file-- open project, and you can just load them, but I didn't find any suitable for S3C2440. So I built a MINI2440.jflash and configured it manually: J-link settings 1. Open J-Flash ARM and enter th
[Microcontroller]
mini2440-i2c driver analysis
In the i2c driver framework of s3c2440, there are two parts, one is i2c-adapter initialization, the other is i2c-driver initialization. For the eeprom that comes with s3c2440, read the code to see what is worth learning and reference. There are several i2c-adapters on s3c2440, each corresponding to an i2c bus. Multi
[Microcontroller]
mini2440-i2c driver analysis
C51 timer and counter timer and counter
Code: #include reg52.h unsigned char a,num; sbit LED1=P1^0; void main() { num=0; EA=1; //Open the general interrupt ET0=1; //Open the timer 0 minute switch TMOD=0X01; //Set to timer 0, mode 1 TH0=(65536-50000)/256; //Install the initial value for timer 0, the timing time of 12 MHz crystal oscillator is 50ms
[Microcontroller]
C51 timer and counter timer and counter
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号