一、可以使用的GPIO管脚
去掉占用调用的GPIO驱动,包括leds,buzzer,camera ov5640,WIFI mt6620 ,Keyboards
- VIDEO_OV5640– Device Drivers
- – Multimedia support(MEDIA_SUPPORT [=y])
- – Video capture adapters(VIDEO_CAPTURE_DRIVERS [=y])(去掉)
- MTK_COMBO_CHIP_MT6620– Device Drivers
- – MediaTek Connectivity Combo Chip Config
- – MediaTek Connectivity Combo Chip Support (MTK_COMBO [=y])(去掉)
- – Select Chip (<choice> [=y])
- Enable LEDS config– Device Drivers
- – Character devices
- – Enable LEDS config
-
Enable BUZZER config
- – Device Drivers
- – Character devices
- – Enable BUZZER config
- Enable Keyboards
- Device Drivers --->
- Input device support --->
- Keyboards --->
static int led_gpios[] = { EXYNOS4_GPL2(0), EXYNOS4_GPK(1), /* Led IO 2个 */ EXYNOS4_GPD0(0), /* BUZZER IO 1个 */ EXYNOS4_GPX1(0), EXYNOS4_GPX1(3),EXYNOS4_GPX1(5),EXYNOS4_GPX1(6), /* 矩阵健盘8个 */ EXYNOS4_GPX3(0),EXYNOS4_GPX2(6),EXYNOS4_GPX2(7),EXYNOS4_GPX3(5), EXYNOS4212_GPJ1(3),EXYNOS4_GPL0(1),EXYNOS4_GPL0(3),EXYNOS4212_GPJ1(0), /* 摄像头14个 */ EXYNOS4212_GPJ1(2),EXYNOS4212_GPJ1(1),EXYNOS4212_GPJ0(7),EXYNOS4212_GPJ0(6), EXYNOS4212_GPJ0(5),EXYNOS4212_GPJ0(4),EXYNOS4212_GPJ0(0),EXYNOS4212_GPJ0(3), EXYNOS4212_GPJ0(1),EXYNOS4212_GPJ0(2), EXYNOS4_GPK3(6),EXYNOS4_GPK3(1),EXYNOS4_GPK3(4),EXYNOS4_GPK3(0), /* WIFI 7个 */ EXYNOS4_GPK3(3),EXYNOS4_GPK3(5),EXYNOS4_GPC1(1), };
二、设计思路
- 通过外部中断来处理电路上升沿和下降沿的跳变处理
- 通过读取IO管脚,来判断是上升沿触发还是下降沿触发
- 使用do_gettimeofday来获取时间戳,从而计算高电平时间
下面是我的源码:
#include <linux/init.h> #include <linux/module.h> /* */ #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/gpio.h> #include <plat/gpio-cfg.h> #include <mach/gpio.h> #include <mach/gpio-exynos4.h> #include <asm/uaccess.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/time.h> #define DRIVER_NAME "ReadPwm" #define DEVICE_NAME "read_pwm" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET"); #define GPIO_CHG_FLT EXYNOS4_GPX1(0) static int up_flag = 0; struct platform_device *dev_int; /* led: KP_COL0, VDD50_EN */ /* BUZZER: MOTOR_PWM */ /* keyboards: CHG_FLT, HOOK_DET, CHG_UOK, XEINT14_BAK, GM_INT1, 6260_GPIO1, CHG_COK, XEINT29/KP_ROW13/ALV_DBG25 */ /* camera: CAM_MCLK, CAM2M_RST, CAM2M_PWDN, CAM_D5, CAM_D7, CAM_D6, CAM_D4, CAM_D3, CAM_D2, CAM_D1, CAM_PCLK, CAM_D0, CAM_VSYNC, CAM_HREF */ /* WIFI: WIFI_D3, WIFI_CMD, WIFI_D1, WIFI_CLK, WIFI_D0, WIFI_D2,GPC1_1 */ struct timeval tv_begin, tv_end; static int interval = 0; struct semaphore sem; static irqreturn_t qint8_interrupt(int irq, void *dev_id) { int ret; ret = gpio_get_value(GPIO_CHG_FLT); if(ret == 0) { do_gettimeofday(&tv_end); if(tv_end.tv_usec - tv_begin.tv_usec > 0) { down(&sem); interval = tv_end.tv_usec - tv_begin.tv_usec; up(&sem); } // if(printk_ratelimit()) { // printk("tv_end.usec:%d - tv_begin.usec:%d = %d ", tv_end.usec, // tv_begin.usec, tv_end.usec - tv_begin.usec); // } } else if(ret == 1) { do_gettimeofday(&tv_begin); } return IRQ_HANDLED; } static int read_pwm_open(struct inode *inode, struct file *file) { printk(KERN_EMERG "read pwm open "); return 0; } static int read_pwm_release(struct inode *inode, struct file *file) { printk(KERN_EMERG "read pwm release "); return 0; } static ssize_t read_pwm_read(struct file *filp, char __user *buff, size_t size, loff_t *ppos) { unsigned int key_value = 0; char temp[2]; int ret; // printk(KERN_EMERG "sizeof(key_value) is %d ", sizeof(key_value)); if(size != sizeof(temp)) { return -1; } down(&sem); key_value = interval; up(&sem); temp[0] = ((key_value)&0xff); temp[1] = ((key_value>>8)&0xff); ret = copy_to_user(buff, temp, sizeof(temp)); return ret; } static struct file_operations read_pwm_ops = { .owner = THIS_MODULE, .open = read_pwm_open, .release = read_pwm_release, .read = read_pwm_read, }; static struct miscdevice read_pwm_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &read_pwm_ops, }; static int read_pwm_probe(struct platform_device *pdv) { int ret; printk(KERN_EMERG " read pwm start initialized "); /* set up gpio */ // ret = gpio_request(GPIO_CHG_FLT, "GPX1_0"); // if(ret < 0) { // printk(KERN_EMERG "request GPIO %d for read pwm failed ", GPIO_CHG_FLT); // return ret; // } // s3c_gpio_cfgpin(GPIO_CHG_FLT, S3C_GPIO_INPUT); // s3c_gpio_setpull(GPIO_CHG_FLT, S3C_GPIO_PULL_NONE); ret = request_irq(IRQ_EINT(8), qint8_interrupt, IRQ_TYPE_EDGE_BOTH, "my_eint8", pdv); if(ret < 0) { printk(KERN_EMERG "request irq 8 failed. "); return 0; } up_flag = 1; dev_int = pdv; sema_init(&sem, 1); /* register */ ret = misc_register(&read_pwm_dev); if(ret < 0) { gpio_free(GPIO_CHG_FLT); misc_deregister(&read_pwm_dev); return -EINVAL; } return 0; } static int read_pwm_remove(struct platform_device *pdv) { printk(KERN_EMERG " read pwm remove "); // gpio_free(GPIO_CHG_FLT); free_irq(IRQ_EINT(8), pdv); misc_deregister(&read_pwm_dev); return 0; } static void read_pwm_shutdown(struct platform_device *pdv) { } static int read_pwm_suspend(struct platform_device *pdv, pm_message_t pmt) { return 0; } static int read_pwm_resume(struct platform_device *pdv) { return 0; } struct platform_driver read_pwm_driver = { .probe = read_pwm_probe, .remove = read_pwm_remove, .shutdown = read_pwm_shutdown, .suspend = read_pwm_suspend, .resume = read_pwm_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, } }; static int read_pwm_init(void) { int DriverState; printk(KERN_EMERG "Read pwm init enter! "); DriverState = platform_driver_register(&read_pwm_driver); printk(KERN_EMERG " DriverState is %d ", DriverState); return 0; } static void read_pwm_exit(void) { printk(KERN_EMERG "Read pwm exit! "); platform_driver_unregister(&read_pwm_driver); } module_init(read_pwm_init); module_exit(read_pwm_exit);
还有一个问题,卸载模块后再装载就会报错,不知道为什么。
app源码:
#include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <sys/stat.h> #define READ_PWM "/dev/read_pwm" int main() { long value = 0; int fd; char buff[2]; int ret; fd = open(READ_PWM, O_RDWR|O_NDELAY); if(fd < 0) { perror("open"); } while(ret = read(fd, buff, sizeof(buff)) >= 0) { printf("value is %d ", buff[0]|buff[1]<<8); usleep(100000); } printf("sizeof(value) is %d ", sizeof(buff)); printf("read return is %d ", ret); return 0; }