[IMX 6 DL][Android 4.4]超音波モジュールHC-SR 04 Linux駆動ソースコード

17645 ワード

Platform: IMX6DL OS: Android 4.4 Kernel branch: 3.0.35
説明:
1.ハードウェアはHC-SR 04モジュールに基づき、自分で検索できる.
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_defconfig
index 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.c
index 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 
 #include 
 
+/*Kris, 20160325, add ultrasnoic device.  {*/
+#ifdef CONFIG_ULTRASONIC
+#include 
+#endif
+/*Kris, 20160325, add ultrasnoic device.  }*/
+
 #define KD() printk("[DEBUG]%d
", __LINE__); /** #define TEK_ANDROID_POWER IMX_GPIO_NR(1, 4) @@ -110,7 +116,7 @@ /*Kris, 20160302, Add head key. }*/ /*Kris, 20160317, Add human sense key. {*/ -#define TEK_HUMEM_SENSE IMX_GPIO_NR(2, 7) +#define TEK_HUMAM_SENSE IMX_GPIO_NR(2, 7) /*Kris, 20160317, Add human sense key. }*/ /*Kris, 20150604, add touchscreen driver. {*/ @@ -152,6 +158,16 @@ #define TEK_HEADPHONE_DET IMX_GPIO_NR(7, 8) #define TEK_PFUZE_INT IMX_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.h index 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/Kconfig index 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/Makefile index 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define US_STATUS_OPEN		0
#define US_STATUS_START		1

//#define ULTRASONIC_USE_PWM

static 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_PWM
			pwm_enable(pdata->pwm);
#endif
			pdata->start = 1;
		}
		break;
	case ULTRASONIC_CMD_STOP:
		if (pdata->start) {
			//disable_irq(pdata->irq);
#ifdef ULTRASONIC_USE_PWM
			pwm_disable(pdata->pwm);
#endif
			pdata->start = 0;
		}
		break;
#ifdef ULTRASONIC_USE_PWM
	case 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;
#endif
	case 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!
"); 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!
"); 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 1000000 if (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
",pdata->c_time.tv_usec, pdata->l_time.tv_usec); //dev_dbg(&us_dev->dev, "interval:%ld
", 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
", 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
"); return -ENODEV; } #ifdef ULTRASONIC_USE_PWM pdata->pwm = pwm_request(pdata->pwm_id, "ultrasonic-pwm"); if (IS_ERR(pdata->pwm)) { dev_err(&pdev->dev, "unable to request PWM for ultrasonic
"); ret = PTR_ERR(pdata->pwm); return -ENODEV; } else dev_dbg(&pdev->dev, "got pwm for ultrasonic
"); //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
", 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
", ret); goto exit_pwm_free; } //Used in user space. ret = misc_register(&ultrasonic_dev); if (ret) { dev_err(&pdev->dev, "ultrasonic_dev register failed
"); goto exit_stop_thread; } platform_set_drvdata(pdev, pdata); printk("#########%s
", __func__); return 0; exit_stop_thread: kthread_stop(p); exit_pwm_free: #ifdef ULTRASONIC_USE_PWM pwm_free(pdata->pwm); #endif return 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 
#include 
#include 
#include 

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 time
	struct timeval c_time;	//current time
	struct 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.c

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    liblog \

LOCAL_MODULE:= ultrasonic_test

include $(BUILD_EXECUTABLE)

ultrasonic_test.c
#if 1
#define LOG_TAG "Ultrasonic"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 

 
#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
",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
",dis); } return 0; } #else #define LOG_TAG "Ultrasonic" #include #include #include #include #include #include #include #include #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
",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
",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