I recently played with the micro2440 of Friendly Arm and realized the function of controlling the LED light on and off with a button. I would like to summarize it here. If there are any errors, I hope experts can point them out. I also hope to help novices who have just learned to drive.
First post the LEDs driver:
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
-
#define DEVICE_NAME "leds"
-
-
static unsigned long led_table [] = {
-
S3C2410_GPB5,
-
S3C2410_GPB6,
-
S3C2410_GPB7,
-
S3C2410_GPB8,
-
};
-
-
static unsigned int led_cfg_table [] = {
-
S3C2410_GPB5_OUTP,
-
S3C2410_GPB6_OUTP,
-
S3C2410_GPB7_OUTP,
-
S3C2410_GPB8_OUTP,
-
};
-
-
static int sbc2440_leds_ioctl(
-
struct inode *inode,
-
struct file *file,
-
unsigned int cmd,
-
unsigned long arg)
-
{
-
switch(cmd) {
-
case 0:
-
case 1:
-
if (arg > 4) {
-
return -SINGLE SELECT;
-
}
-
s3c2410_gpio_setpin(led_table[arg], !cmd);
-
return 0;
-
default:
-
return -SINGLE SELECT;
-
}
-
}
-
-
static struct file_operations dev_fops = {
-
.owner = THIS_MODULE,
-
.ioctl = sbc2440_leds_ioctl,
-
};
-
-
static struct miscdevice misc = {
-
.minor = MISC_DYNAMIC_MINOR,
-
.name = DEVICE_NAME,
-
.fops = &dev_fops,
-
};
-
-
static int __init dev_init(void)
-
{
-
int ret;
-
-
int i;
-
-
for (i = 0; i < 4; i++) {
-
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
-
s3c2410_gpio_setpin(led_table[i], 0);
-
}
-
-
ret = misc_register(&misc);
-
-
printk (DEVICE_NAME"tinitializedn");
-
-
return ret;
-
}
-
-
static void __exit dev_exit(void)
-
{
-
misc_deregister(&misc);
-
}
-
-
module_init(dev_init);
-
module_exit(dev_exit);
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("FriendlyARM Inc.");
The key point of this driver is to provide an ioctl device method. When the ioctl (leds' fd, cmd, arg) system call is used in the application, the system will enter the kernel state and call sbc2440_leds_ioctl() to control the on and off of the light.
The buttons driver is posted below:
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define DEVICE_NAME "buttons"
-
-
struct button_irq_desc {
-
int irq;
-
int pin;
-
int pin_setting;
-
int number;
-
char *name;
-
};
-
-
#if !defined (CONFIG_QQ2440_BUTTONS)
-
static struct button_irq_desc button_irqs [] = {
-
{IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"},
-
{IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"},
-
{IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"},
-
{IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"},
-
{IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"},
-
{IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},
-
};
-
#else /* means QQ */
-
static struct button_irq_desc button_irqs [] = {
-
{IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 0, "KEY0"},
-
{IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG3_EINT11, 1, "KEY1"},
-
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY2"},
-
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY3"},
-
{ -1, -1, -1, 4, "KEY4"},
-
{ -1, -1, -1, 5, "KEY5"},
-
};
-
#endif
-
static volatile char key_values [] = {'0', '0', '0', '0', '0', '0'};
-
-
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
-
-
static volatile int ev_press = 0;
-
-
-
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
-
{
-
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
-
int down;
-
-
// delay(0);
-
down = !s3c2410_gpio_getpin(button_irqs->pin);
-
-
if (down != (key_values[button_irqs->number] & 1)) { // Changed
-
-
key_values[button_irqs->number] = '0' + down;
-
-
ev_press = 1;
-
wake_up_interruptible(&button_waitq);
-
}
-
-
return IRQ_RETVAL(IRQ_HANDLED);
-
}
-
-
-
static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
-
{
-
int i;
-
int err = 0;
-
-
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
-
if (button_irqs[i].irq < 0) {
-
continue;
-
}
-
err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
-
button_irqs[i].name, (void *)&button_irqs[i]);
-
if (err)
-
break;
-
}
-
-
if (err) {
-
i--;
-
for (; i >= 0; i--) {
-
if (button_irqs[i].irq < 0) {
-
continue;
-
}
-
disable_irq(button_irqs[i].irq);
-
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
-
}
-
return -EBUSY;
-
}
-
-
ev_press = 1;
-
-
return 0;
-
}
-
-
-
static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
-
{
-
int i;
-
-
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
-
if (button_irqs[i].irq < 0) {
-
continue;
-
}
-
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
-
}
-
-
return 0;
-
}
-
-
-
static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
-
{
-
unsigned long err;
-
-
if (!ev_press) {
-
if (filp->f_flags & O_NONBLOCK)
-
return -EAGAIN;
-
else
-
wait_event_interruptible(button_waitq, ev_press);
-
}
-
-
ev_press = 0;
-
-
err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
-
-
return err ? -EFAULT : min(sizeof(key_values), count);
-
}
-
-
static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
-
{
-
unsigned int mask = 0;
-
poll_wait(file, &button_waitq, wait);
-
if (ev_press)
-
mask |= POLLIN | POLLRDNORM;
-
return mask;
-
}
-
-
-
static struct file_operations dev_fops = {
-
.owner = THIS_MODULE,
-
.open = s3c24xx_buttons_open,
-
.release = s3c24xx_buttons_close,
-
.read = s3c24xx_buttons_read,
-
.poll = s3c24xx_buttons_poll,
-
};
-
-
static struct miscdevice misc = {
-
.minor = MISC_DYNAMIC_MINOR,
-
.name = DEVICE_NAME,
-
.fops = &dev_fops,
-
};
-
-
static int __init dev_init(void)
-
{
-
int ret;
-
-
ret = misc_register(&misc);
-
-
printk (DEVICE_NAME"tinitializedn");
-
-
return ret;
-
}
-
-
static void __exit dev_exit(void)
-
{
-
misc_deregister(&misc);
-
}
-
-
module_init(dev_init);
-
module_exit(dev_exit);
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("FriendlyARM Inc.");
The key to this driver (For a detailed analysis of the button driver, please see my other article mini2440_buttons.c driver interpretation http://www.linuxidc.com/Linux/2011-07/38768.htm )
1. It is the device method of s3c24xx_buttons_read. When the read (buttons fs, key status array, how many bits to read) system call is used in the application, the kernel state will be entered to call the s3c24xx_buttons_read function. This function will enter the interruptible sleep state through wait _event_interruptible() and wait for the arrival of the interrupt.
2. The buttons_interrupt interrupt service function is defined, which processes the corresponding key value and wakes up the sleep state.
The application is as follows:
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
Previous article:Interpretation of mini2440_buttons.c driver
Next article:About the serial port number of S3C2440
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- Tuya Smart Module SDK Development Course Series——1. SoC Development Environment Construction
- Designed a Simon game ruler with 4 LEDs and switches
- TMS320C6711 serial communication initialization program
- Data searchRSL10-COIN-GEVB
- MSP430 MCU Development Record (5)
- EEWORLD University Hall----Using JTAG with UCD3138
- Share: What is the use of the 100 Ω resistor before the MOSFET gate?
- POL thermal resistance measurement and SOA evaluation
- Registration for the live broadcast with prizes is in progress: Infineon's intelligent motor drive solution
- [TI Live Review] TI Robot System Learning Kit Lecture (including video, ppt, QA)