基于i.MX6ULL平台设计实现掉电检测功能,首先选择一路IO,利用IO电平变化触发中断,在编写驱动时捕获该路GPIO的中断,然后在中断响应函数中发送信号通知应用程序掉电发生了。
图 1.1 掉电信号IO
驱动代码:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/switch_to.h>
#include <asm/uaccess.h>
#include <asm/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#define power_MAJOR 200
static struct class *my_class;
static struct fasync_struct *fasync_queue; //异步通知队列
#define GPIO_NUM 1 //中断引脚为:GPIO1_1
static unsigned int irq_num;
/* 打开 */
int power_open(struct inode *inode,struct file *filp){
return 0;
}
/* 关闭 */
int power_release(struct inode *inode,struct file *filp){
return 0;
}
ssize_t power_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos){
return count;
}
ssize_t power_write(struct file *file,const char __user *buf,size_t count,loff_t *f_pos){
return count;
}
static int my_fasync(int fd, struct file * filp, int on)
{
int retval;
retval=fasync_helper(fd,filp,on,&fasync_queue);
/*将该设备登记到fasync_queue队列中去*/
if(retval<0)
return retval;
return 0;
}
static const struct file_operations simple_fops={
.owner=THIS_MODULE,
.open=power_open,
.release=power_release,
.read=power_read,
.write=power_write,
.fasync=my_fasync,
};
/* 在中断服务函数中向应用层发送消息-异步通知 */
static irqreturn_t irq_callback (int irqno, void *dev_id){
printk("irq power-detect working !\n");
if (fasync_queue) {
kill_fasync(&fasync_queue, SIGIO, POLL_IN);
}
return IRQ_HANDLED;
}
int power_init_module(void){
int rtn;
int ret;
/* 注册设备驱动 */
ret = register_chrdev(power_MAJOR,"power-detect-test",&simple_fops);
if(ret<0){
printk("Unable to register character device %d!/n",ret);
return ret;
}
/* 自动创建设备节点 */
my_class = class_create(THIS_MODULE, "my_class");
device_create(my_class, NULL, MKDEV(power_MAJOR, 0), NULL,"powerdetect");
/*gpio申请*/
rtn = gpio_request(GPIO_NUM, "my_irq");
if(rtn!=0){
printk("my_irq irq pin request io failed.\n");
}
rtn = gpio_direction_input(GPIO_NUM);
if(rtn<0){
printk("gpio_direction_input() failed !\n");
}
/*获取gpio中断号*/
irq_num = gpio_to_irq(GPIO_NUM);
/*GPIO中断服务函数注册,*/ /*下降沿触发*/
rtn = request_irq(irq_num, irq_callback,IRQF_TRIGGER_FALLING,"my_irq", NULL);
if (rtn<0) {
printk("my_irq request irq false\n");
} else {
printk("my_irq request irq success: %d\n",irq_num);
}
printk("module_init sucessful!!!\n");
return 0;
}
/* 卸载 */
void power_cleanup_module(void){
/* 卸载相应的设备驱动 */
unregister_chrdev(power_MAJOR,"power-detect-test");
device_destroy(my_class,MKDEV(power_MAJOR, 0));
class_destroy(my_class);
/*释放GPIO*/
gpio_free(GPIO_NUM);
printk("module_exit sucessful!!!\n");
}
/* 宏实现 */
module_init(power_init_module);
module_exit(power_cleanup_module);
/* 开源许可声明 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zou");
应用代码:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
static int fd;
/* 内核产生异步通知,调用该应用层函数处理 */
void sigterm_handler(int signo)
{
printf("app irq work !!!\n");
}
int main(void)
{
int oflags;
fd=open("/dev/powerdetect",O_RDWR); //打开设备文件
/* 启动异步通知信号驱动机制 */
signal(SIGIO, sigterm_handler);
fcntl(fd, F_SETOWN, getpid());
oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, oflags | FASYNC);
/*建立一个死循环,防止程序结束 */
while(1)
{
printf("sleep\n");
usleep(200000); //2ms
}
close(fd);
return 0;
}
将驱动编译成模块,上电加载并执行应用程序后,将电压缓慢下调至掉电临界点。触发GPIO下降沿中断,并提供应用程序掉电信号。
图1..2 掉电检测