基于i.MX6ULL的掉電檢測設(shè)計與軟件測試
基于i.MX6ULL平臺設(shè)計實現(xiàn)掉電檢測功能,首先選擇一路IO,利用IO電平變化觸發(fā)中斷,在編寫驅(qū)動時捕獲該路GPIO的中斷,然后在中斷響應(yīng)函數(shù)中發(fā)送信號通知應(yīng)用程序掉電發(fā)生了。
圖1.1掉電信號IO
驅(qū)動代碼:
#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>
#definepower_MAJOR 200
staticstruct class *my_class;
staticstruct fasync_struct *fasync_queue; //異步通知隊列
#defineGPIO_NUM 1 //中斷引腳為:GPIO1_1
staticunsigned int irq_num;
/* 打開 */
intpower_open(struct inode *inode,struct file *filp){
return 0;
}
/* 關(guān)閉 */
intpower_release(struct inode *inode,struct file *filp){
return 0;
}
ssize_tpower_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos){
return count;
}
ssize_tpower_write(struct file *file,const char __user *buf,size_t count,loff_t*f_pos){
return count;
}
staticint my_fasync(int fd, struct file * filp, int on)
{
int retval;
retval=fasync_helper(fd,filp,on,&fasync_queue);
/*將該設(shè)備登記到fasync_queue隊列中去*/
if(retval<0)
return retval;
return 0;
}
staticconst struct file_operations simple_fops={
.owner=THIS_MODULE,
.open=power_open,
.release=power_release,
.read=power_read,
.write=power_write,
.fasync=my_fasync,
};
/* 在中斷服務(wù)函數(shù)中向應(yīng)用層發(fā)送消息-異步通知 */
staticirqreturn_t irq_callback (int irqno, void *dev_id){
printk("irq power-detectworking !\n");
if (fasync_queue) {
kill_fasync(&fasync_queue, SIGIO,POLL_IN);
}
return IRQ_HANDLED;
}
intpower_init_module(void){
int rtn;
int ret;
/* 注冊設(shè)備驅(qū)動 */
ret =register_chrdev(power_MAJOR,"power-detect-test",&simple_fops);
if(ret<0){
printk("Unable toregister character device %d!/n",ret);
return ret;
}
/* 自動創(chuàng)建設(shè)備節(jié)點 */
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 pinrequest 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中斷服務(wù)函數(shù)注冊,*/ /*下降沿觸發(fā)*/
rtn = request_irq(irq_num,irq_callback,IRQF_TRIGGER_FALLING,"my_irq", NULL);
if (rtn<0) {
printk("my_irq requestirq false\n");
} else {
printk("my_irq requestirq success: %d\n",irq_num);
}
printk("module_initsucessful!!!\n");
return 0;
}
/* 卸載 */
voidpower_cleanup_module(void){
/* 卸載相應(yīng)的設(shè)備驅(qū)動 */
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_exitsucessful!!!\n");
}
/* 宏實現(xiàn) */
module_init(power_init_module);
module_exit(power_cleanup_module);
/* 開源許可聲明 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zou");
應(yīng)用代碼:
#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<fcntl.h>
staticint fd;
/* 內(nèi)核產(chǎn)生異步通知,調(diào)用該應(yīng)用層函數(shù)處理 */
voidsigterm_handler(int signo)
{
printf("app irq work !!!\n");
}
intmain(void)
{
int oflags;
fd=open("/dev/powerdetect",O_RDWR); //打開設(shè)備文件
/* 啟動異步通知信號驅(qū)動機制 */
signal(SIGIO, sigterm_handler);
fcntl(fd, F_SETOWN, getpid());
oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, oflags | FASYNC);
/*建立一個死循環(huán),防止程序結(jié)束 */
while(1)
{
printf("sleep\n");
usleep(200000); //2ms
}
close(fd);
return 0;
}
將驅(qū)動編譯成模塊,上電加載并執(zhí)行應(yīng)用程序后,將電壓緩慢下調(diào)至掉電臨界點。觸發(fā)GPIO下降沿中斷,并提供應(yīng)用程序掉電信號。
圖1..2掉電檢測