[IMX6DL]超声波模块HC-SR04 Linux驱动源代码

来源:互联网 发布:阿里云系统怎么样os 编辑:程序博客网 时间:2024/05/19 17:25

Platform: IMX6DL
OS: Android 4.4
Kernel branch: 3.0.35


说明:

1. 硬件基于HC-SR04模块,可自行查找。

2. 代码PWM模块用于测试中断响应性能, 背光部分注释掉是因为和PWM复用了。

3. 测试中断响应性能时不要使用在中断上半部使用printk()方式,否则延时会到ms级。

4. 代码中注册的字符设备可不需要,创建的内核线程用于控制时序。

3. 由于超声波采用的是普通的GPIO中断,而且精度需要达到us级,当有许多高优先级的中断需要处理时,

驱动响应会延迟导致得到的时间不同,稳定性会大大下降,只可作为参考,如果要商用最好使用专用单片机模块处理测距。


源代码:

配置:

diff --git a/arch/arm/configs/imx6_tek_android_defconfig b/arch/arm/configs/imx6_tek_android_defconfigindex d26fe73..18125d0 100644--- a/arch/arm/configs/imx6_tek_android_defconfig+++ b/arch/arm/configs/imx6_tek_android_defconfig@@ -12,7 +12,7 @@ CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y CONFIG_KTIME_SCALAR=y CONFIG_HAVE_PROC_CPU=y-CONFIG_STACKTRACE_SUPPORT=y+CONFIG_STACKTRACE_SUPPOR100T=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y@@ -1189,7 +1189,8 @@ CONFIG_MXS_PERFMON=m # CONFIG_C2PORT is not set #Kris,20160226,Add MIC driver. CONFIG_XMF10411=y-+#Kris, 20160325, add ultrasnoic device.+CONFIG_ULTRASONIC=y # # EEPROM support #diff --git a/arch/arm/mach-mx6/board-mx6-tek.c b/arch/arm/mach-mx6/board-mx6-tek.cindex bea16af..8b0327f 100644--- a/arch/arm/mach-mx6/board-mx6-tek.c+++ b/arch/arm/mach-mx6/board-mx6-tek.c@@ -84,6 +84,12 @@ #include <sound/tlv320aic32x4.h> #include <mach/imx_rfkill.h> +/*Kris, 20160325, add ultrasnoic device.  {*/+#ifdef CONFIG_ULTRASONIC+#include <linux/ultrasonic.h>+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/+ #define KD() printk("[DEBUG]%d\n", __LINE__); /** #define TEK_ANDROID_POWERIMX_GPIO_NR(1, 4)@@ -110,7 +116,7 @@ /*Kris, 20160302, Add head key. }*/  /*Kris, 20160317, Add human sense key. {*/-#define TEK_HUMEM_SENSEIMX_GPIO_NR(2, 7)+#define TEK_HUMAM_SENSEIMX_GPIO_NR(2, 7) /*Kris, 20160317, Add human sense key. }*/  /*Kris, 20150604, add touchscreen driver. {*/@@ -152,6 +158,16 @@ #define TEK_HEADPHONE_DETIMX_GPIO_NR(7, 8) #define TEK_PFUZE_INTIMX_GPIO_NR(7, 13) ++/*Kris, 20160325, add ultrasnoic device.  {*/+#ifdef CONFIG_ULTRASONIC+#define ULTRASONIC_DET IMX_GPIO_NR(2, 6)+#define ULTRASONIC_CTRL_GPIO  IMX_GPIO_NR(2, 3)+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/++ @@ -664,6 +680,27 @@ static struct platform_device tek_battery_device = { #endif /*Kris, 20150611, add pseudo battery device. }*/ +/*Kris, 20160325, add ultrasnoic device.  {*/+#ifdef CONFIG_ULTRASONIC+struct ultrasonic_platform_data ultrasonic_data = {+.pwm_id = 0,+.pwm_duty_ns = 250000,+.pwm_period_ns = 500000,+.irq = gpio_to_irq(ULTRASONIC_DET),+.ctrl_gpio = ULTRASONIC_CTRL_GPIO,+};++static struct platform_device ultrasonic_device = {+.name= "e-ultrasonic",+.id= -1,+.dev= {+.platform_data = &ultrasonic_data,+}+};+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/++  struct imx_vout_mem { resource_size_t res_mbase;@@ -719,12 +756,16 @@ static void daogou_power_on(void) /*Kris, 20150609, add touchscreen driver. }*/ } +/*Kris, 20160325, add ultrasnoic device.  {*/+#ifndef CONFIG_ULTRASONIC static struct platform_pwm_backlight_data mx6_tek_pwm_backlight_data = { .pwm_id = 0, .max_brightness = 248, .dft_brightness = 128, .pwm_period_ns = 50000, };+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/  static struct mxc_dvfs_platform_data tek_dvfscore_data = { .reg_id = "VDDCORE",@@ -986,7 +1027,12 @@ static void __init mx6_tek_board_init(void) imx6q_add_mxc_pwm(1); imx6q_add_mxc_pwm(2); imx6q_add_mxc_pwm(3);++/*Kris, 20160325, add ultrasnoic device.  {*/+#ifndef CONFIG_ULTRASONIC imx6q_add_mxc_pwm_backlight(0, &mx6_tek_pwm_backlight_data);+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/  imx6q_add_otp(); imx6q_add_viim();@@ -1041,6 +1087,12 @@ static void __init mx6_tek_board_init(void) #endif /*Kris, 20150611, add pseudo battery device. }*/ ++/*Kris, 20160325, add ultrasnoic device.  {*/+#ifdef CONFIG_ULTRASONIC+platform_device_register(&ultrasonic_device);+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/ }  extern void __iomem *twd_base;diff --git a/arch/arm/mach-mx6/board-mx6dl-tek.h b/arch/arm/mach-mx6/board-mx6dl-tek.hindex 184a0e3..be7725f 100644--- a/arch/arm/mach-mx6/board-mx6dl-tek.h+++ b/arch/arm/mach-mx6/board-mx6dl-tek.h@@ -149,6 +149,13 @@ static iomux_v3_cfg_t mx6dl_tek_pads[] = { #endif /*Kris, 20160317, Add human sense key. }*/ +/*Kris, 20160325, add ultrasnoic device.  {*/+#ifdef CONFIG_ULTRASONIC+MX6DL_PAD_NANDF_D3__GPIO_2_3,+MX6DL_PAD_NANDF_D6__GPIO_2_6,+#endif+/*Kris, 20160325, add ultrasnoic device.  }*/+ /* USDHC3 */ MX6DL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, MX6DL_PAD_SD3_CMD__USDHC3_CMD_50MHZ,diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfigindex 6e660e9..910d286 100644--- a/drivers/misc/Kconfig+++ b/drivers/misc/Kconfig@@ -543,6 +543,11 @@ config XMF10411 tristate "XMF10411 sound support" depends on I2C +#Kris, 20160325, add ultrasnoic device.+config ULTRASONIC+bool "Ultrasonic driver"+default n+ source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig"diff --git a/drivers/misc/Makefile b/drivers/misc/Makefileindex fbe4f1f..4099a15 100644--- a/drivers/misc/Makefile+++ b/drivers/misc/Makefile@@ -55,3 +55,6 @@ obj-$(CONFIG_SENSORS_AK8975)+= akm8975.o  #Kris,20160226,Add MIC driver. obj-$(CONFIG_XMF10411) += xmf10411.o++#Kris, 20160325, add ultrasnoic device.+obj-$(CONFIG_ULTRASONIC) += ultrasonic.o

驱动:

ultrasonic.c

/* drivers/misc/ultrasonic.c - ultrasonic  driver * * Copyright (C) 2007-2008 HTC Corporation. * Author: Kris Fei * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * */ #define DEBUG 1#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/miscdevice.h>#include <linux/gpio.h>#include <linux/uaccess.h>#include <linux/delay.h>#include <linux/workqueue.h>#include <linux/platform_device.h>#include <linux/pwm.h>#include <linux/ultrasonic.h>#include <linux/fs.h>#include <linux/wait.h>#include <linux/time.h>#include <linux/sched.h>#include <linux/kthread.h>#define US_STATUS_OPEN0#define US_STATUS_START1//#define ULTRASONIC_USE_PWMstatic struct platform_device *us_dev;static struct ultrasonic_platform_data *us_pd;//static DECLARE_WAIT_QUEUE_HEAD(us_waitq);static int ultrasonic_open(struct inode *inode, struct file *file){if (test_and_set_bit(US_STATUS_OPEN, &us_pd->status))return -EBUSY;return 0;}static int ultrasonic_release(struct inode *inode, struct file *file){clear_bit(US_STATUS_OPEN, &us_pd->status);return 0;}static long ultrasonic_ioctl(struct file *file, unsigned int cmd, unsigned long arg){void __user *argp = (void __user *) arg;struct ultrasonic_platform_data *pdata = file->private_data;switch (cmd) {case ULTRASONIC_CMD_START:if (!pdata->start) {do_gettimeofday(&pdata->l_time);#ifdef ULTRASONIC_USE_PWMpwm_enable(pdata->pwm);#endifpdata->start = 1;}break;case ULTRASONIC_CMD_STOP:if (pdata->start) {//disable_irq(pdata->irq);#ifdef ULTRASONIC_USE_PWMpwm_disable(pdata->pwm);#endifpdata->start = 0;}break;#ifdef ULTRASONIC_USE_PWMcase ULTRASONIC_CMD_SET_DUTY:if (pdata->start)return -EFAULT;if(copy_from_user(&pdata->pwm_duty_ns, argp, sizeof(pdata->pwm_duty_ns)))return -EFAULT;pwm_config(pdata->pwm, pdata->pwm_duty_ns, pdata->pwm_period_ns);break;case ULTRASONIC_CMD_GET_DUTY:if(copy_to_user(argp, &pdata->pwm_duty_ns, sizeof(pdata->pwm_duty_ns)))return -EFAULT;break;#endifcase ULTRASONIC_CMD_GET_DIS:mutex_lock(&pdata->u_mutex);if(copy_to_user(argp, &pdata->dis_mm, sizeof(pdata->dis_mm))) {mutex_unlock(&pdata->u_mutex);return -EFAULT;}mutex_unlock(&pdata->u_mutex);break;default:printk("Unknown command!\n");return -EINVAL;}return 0;}static irqreturn_t ultrasonic_irq_handler(int irq, void *data){struct ultrasonic_platform_data *pdata = data;//Don't add printk(), or it will increase the time of the handler!!!if (test_bit(US_STATUS_START, &pdata->status)) {if (atomic_read(&pdata->count) == 0) {//Rising edge, record the start time.do_gettimeofday(&pdata->l_time);atomic_inc(&pdata->count);} else if (atomic_read(&pdata->count) == 1) {//Falling edge, record the stop time.do_gettimeofday(&pdata->c_time);//Following two filter other unuseful interrupts.atomic_inc(&pdata->count);clear_bit(US_STATUS_START, &pdata->status);}}return IRQ_HANDLED;}static int ultrasonic_thread(void *arg){struct ultrasonic_platform_data *pdata = arg;//enable interrupt before start test.enable_irq(pdata->irq);while(1) {//dev_dbg(&us_dev->dev, "test start!\n");atomic_set(&pdata->count, 0);set_bit(US_STATUS_START, &pdata->status);/*Following is the timing of starting ultrasonic.*///Low active.gpio_set_value(pdata->ctrl_gpio, 0);//follow the spec, at least 10us.udelay(30);gpio_set_value(pdata->ctrl_gpio, 1);//Control test peroid.msleep(900);/*Calculate distance from time interval.*///Max is 1000000if (pdata->c_time.tv_usec < pdata->l_time.tv_usec) pdata->interval = 1000000 - pdata->l_time.tv_usec + pdata->c_time.tv_usec;else pdata->interval =pdata->c_time.tv_usec - pdata->l_time.tv_usec;dev_dbg(&us_dev->dev,"c:%ld l:%ld\n",pdata->c_time.tv_usec, pdata->l_time.tv_usec);//dev_dbg(&us_dev->dev, "interval:%ld \n", pdata->interval );mutex_lock(&pdata->u_mutex);pdata->dis_mm =  (170 * pdata->interval)/1000;mutex_unlock(&pdata->u_mutex);dev_dbg(&us_dev->dev, "distance is :%ld mm\n", pdata->dis_mm);}return 0;}static const struct file_operations ultrasonic_fops = {.owner = THIS_MODULE,.open = ultrasonic_open,.release = ultrasonic_release,.unlocked_ioctl = ultrasonic_ioctl,};static struct miscdevice ultrasonic_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "ultrasonic",.fops = &ultrasonic_fops,};static int __devinit ultrasonic_probe(struct platform_device *pdev){struct ultrasonic_platform_data *pdata = pdev->dev.platform_data;int ret;unsigned long irq_flags;struct task_struct *p;if (pdata == NULL) {dev_err(&pdev->dev, "missing platform data\n");return -ENODEV;}#ifdef ULTRASONIC_USE_PWMpdata->pwm = pwm_request(pdata->pwm_id, "ultrasonic-pwm");if (IS_ERR(pdata->pwm)) {dev_err(&pdev->dev, "unable to request PWM for ultrasonic\n");ret = PTR_ERR(pdata->pwm);return -ENODEV;} elsedev_dbg(&pdev->dev, "got pwm for ultrasonic\n");//default config.pwm_config(pdata->pwm, pdata->pwm_duty_ns, pdata->pwm_period_ns);pwm_enable(pdata->pwm);#endif//protect data to be read in user space.mutex_init(&pdata->u_mutex);//gpio init, control it to start and stop.gpio_request(pdata->ctrl_gpio, "ultrasonic control gpio");gpio_direction_output(pdata->ctrl_gpio, 1);gpio_set_value(pdata->ctrl_gpio, 1);//request irq.irq_flags = IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING;ret = devm_request_threaded_irq(&pdev->dev, pdata->irq,  ultrasonic_irq_handler,NULL,  irq_flags, "ultrasonic-irq", pdata);if (ret) {dev_err(&pdev->dev, "request ultrasnoic-irq failed: %d\n", ret);goto exit_pwm_free;}//enable later.disable_irq(pdata->irq);pdata->status = 0;pdata->start = 0;us_dev = pdev;us_pd = pdata;//core thread to run and caculate.p = kthread_run(ultrasonic_thread, pdata, "us kthread");if (IS_ERR(p)) {ret = PTR_ERR(p);dev_err(&pdev->dev, "create ultrasnoic core thread failed: %d\n", ret);goto exit_pwm_free;}//Used in user space.ret = misc_register(&ultrasonic_dev);if (ret) {dev_err(&pdev->dev, "ultrasonic_dev register failed\n");goto exit_stop_thread;}platform_set_drvdata(pdev, pdata);printk("#########%s\n", __func__);return 0;exit_stop_thread:kthread_stop(p);exit_pwm_free:#ifdef ULTRASONIC_USE_PWMpwm_free(pdata->pwm);#endifreturn ret;}static int __devexit ultrasonic_remove(struct platform_device *pdev){struct ultrasonic_platform_data *pdata = pdev->dev.platform_data;misc_deregister(&ultrasonic_dev);pwm_free(pdata->pwm);return 0;}static struct platform_driver ultrasonic_driver = {.driver= {.name= "e-ultrasonic",.owner= THIS_MODULE,},.probe= ultrasonic_probe,.remove= __devexit_p(ultrasonic_remove),};static int __init ultrasonic_init(void){return platform_driver_register(&ultrasonic_driver);}static void __exit ultrasonic_exit(void){platform_driver_unregister(&ultrasonic_driver);}module_init(ultrasonic_init);module_exit(ultrasonic_exit);MODULE_AUTHOR("Kris Fei");MODULE_DESCRIPTION("Ultrasonic driver");MODULE_LICENSE("GPL");
ultrasonic.h:

#ifndef __ULTRASONIC_H__#define __ULTRASONIC_H__#include <linux/pwm.h>#include <linux/time.h>#include <linux/mutex.h>#include <linux/types.h>struct ultrasonic_platform_data {struct pwm_device*pwm;u32 irq;u8 pwm_id;u32 pwm_period_ns;u32 pwm_duty_ns;long dis_mm;struct timeval l_time;//last timestruct timeval c_time;//current timestruct mutex u_mutex;u8 start;u8 done;u32 ctrl_gpio;//control start and stop.unsigned long status;atomic_t count;long interval; struct timespec now;struct timespec old;long t;};#define ULTRASONIC_CMD_START_IOW(0, 1, int)#define ULTRASONIC_CMD_STOP_IOW(0, 2, int)#define ULTRASONIC_CMD_SET_DUTY_IOW(0, 3, int)#define ULTRASONIC_CMD_GET_DUTY_IOW(0, 4, int)#define ULTRASONIC_CMD_GET_DIS_IOW(0, 5, int)#endif

测试程序:

Android.mk

# Copyright 2006 The Android Open Source Project LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= ultrasonic_test.cLOCAL_SHARED_LIBRARIES := \    libcutils \    liblog \LOCAL_MODULE:= ultrasonic_testinclude $(BUILD_EXECUTABLE)

ultrasonic_test.c

#if 1#define LOG_TAG "Ultrasonic"#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <string.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h>#include <utils/Log.h>  #define ULTRASONIC_CMD_START_IOW(0, 1, int)#define ULTRASONIC_CMD_STOP_IOW(0, 2, int)#define ULTRASONIC_CMD_GET_DIS_IOW(0, 5, int) int main(int argc, const char *argv[]){    int fd ;    int ret;    long dis;    fd = open("/dev/ultrasonic",O_RDWR);    if(fd < 0){        ALOGE("Fail ot open");        return -1;    }    ALOGI("open successful ,fd = %d\n",fd);        ret = ioctl(fd,ULTRASONIC_CMD_START,NULL);    if(ret < 0){        ALOGE("Fail to ioctl");        return -1;    }while(1) {ret = ioctl(fd,ULTRASONIC_CMD_GET_DIS,&dis);if(ret < 0){ALOGE("Fail to ioctl");return -1;}ALOGI("dis:%ld\n",dis);}    return 0;} #else#define LOG_TAG "Ultrasonic"#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <string.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h>#include <utils/Log.h>#define ULTRASONIC_CMD_START_IOW(0, 1, int)#define ULTRASONIC_CMD_STOP_IOW(0, 2, int)#define ULTRASONIC_CMD_GET_DIS_IOW(0, 5, int)class Ultrasonic{public:Ultrasonic();~Ultrasonic();int init();long getDistance();private:int fd;int ret;long distance;};Ultrasonic::Ultrasonic():fd(-1), ret(-1), distance(-1){}int Ultrasonic::init(){fd = open("/dev/ultrasonic",O_RDWR);    if(fd < 0){        ALOGE("Fail ot open");        return -1;    }    ALOGI("open /dev/ultrasonic successful ,fd = %d\n",fd);        ret = ioctl(fd,ULTRASONIC_CMD_START,NULL);    if(ret < 0){        ALOGE("Fail to ioctl");        return -1;    }        return 0;}long Ultrasonic::getDistance(){ret = ioctl(fd,ULTRASONIC_CMD_GET_DIS,&distance);if(ret < 0){ALOGE("Fail to ioctl");return -1;}ALOGI("dis:%ld\n",distance);return distance;}Ultrasonic::~Ultrasonic(){if (fd > 0) {ret = ioctl(fd,ULTRASONIC_CMD_STOP,NULL);if(ret < 0){ALOGE("Fail to ioctl");}close(fd);}}#endif


1 0
原创粉丝点击