zoukankan      html  css  js  c++  java
  • 4412 4路pwm输出

    一、4412 xpwmTOUT1

    这是4412的GPD0_1路,itop中被使用为LCD的背光电路的pwm功能。因此如果使用教程中的代码,同样操作GPD0_1是行不通的。

    会出现错误,所以需要解除在内核中的占用

    修改arch/arm/mach-exynos/mach-itop4412.c,找到并注释

        samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data);

    在内核中取消相关的模块编译,(不确定)

    Device Driver>>Graphics support>>Backlight & LCD device support(取消)

    然后在平台文件中增加注册设备:

        &s3c_device_timer[1],

    然后是测试代码:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/platform_device.h>
    #include <linux/fb.h>
    #include <linux/backlight.h>
    #include <linux/err.h>
    #include <linux/pwm.h>
    #include <linux/slab.h>
    #include <linux/miscdevice.h>
    #include <linux/delay.h>
    #include <linux/gpio.h>
    #include <mach/gpio.h>
    #include <plat/gpio-cfg.h>
    #include <linux/ioctl.h>
    #include <asm-generic/uaccess.h>
    
    #define DEVICE_NAME "my_pwm3_dev"
    #define DRIVER_NAME "my_pwm3_drv"
    
    #define PWM_MAGIC 'p'
    #define PWM_MAX_NR 3
    
    #define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
    #define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
    #define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)
    
    #define NS_IN_1HZ                               (1000000000UL)
    
    #define BUZZER_PWM_ID                   0
    #define PWM1_ID                                 1
    #define PWM2_ID                 2
    #define PWM3_ID                 3
    
    
    #define BUZZER_PMW_GPIO EXYNOS4_GPD0(0)
    #define PWM1_GPIO               EXYNOS4_GPD0(1)
    #define PWM2_GPIO       EXYNOS4_GPD0(2)
    #define PWM3_GPIO       EXYNOS4_GPD0(3)
    
    static struct pwm_device *pwm4buzzer;
    static struct semaphore lock;
    static int period_ns = 1000;
    static unsigned long freq = 50;
    static unsigned long duty = 2;
    
    static void pwm_set_freq(void)
    {
        //配置周期
        period_ns = NS_IN_1HZ / freq;
        //配置占空比
            if(duty < 1)
                    duty = 1;
        pwm_disable(pwm4buzzer);
        pwm_config(pwm4buzzer, period_ns / duty, period_ns);
        pwm_enable(pwm4buzzer);
        //配置相应的GPIO,蜂鸣器IO配置成PWM输出模式
        s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_SFN(2));
    }
    
    static void pwm_stop(void)
    {
        s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);
    
        pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
        pwm_disable(pwm4buzzer);
    }
    
    static int ops_pwm_open(struct inode *inode, struct file *file)
    {
        if(!down_trylock(&lock))
            return 0;
        else
            return -EBUSY;
    }
    
    static int ops_pwm_close(struct inode *inode, struct file *file)
    {
        up(&lock);
        return 0;
    }
    
    static long ops_pwm_ioctl(struct file *filep, unsigned int cmd,
                    unsigned long arg)
    {
        if(_IOC_TYPE(cmd)!=PWM_MAGIC) return -EINVAL;
        if(_IOC_NR(cmd) > PWM_MAX_NR) return -EINVAL;
    
        switch(cmd) {
        case PWM_IOCTL_SET_FREQ:
            if(arg == 0)
                return -EINVAL;
            get_user(freq, (unsigned long __user *)arg);
            printk(KERN_EMERG "freq is %ld
    ", freq);
            pwm_set_freq();
            break;
        case PWM_IOCTL_STOP:
            pwm_stop();
                    break;
            case PWM_IOCTL_SET_DUTY:
            get_user(duty, (unsigned long __user *)arg);
            printk(KERN_EMERG "duty is %ld
    ", duty);
            pwm_set_freq();
                    break;
        default:
            pwm_stop();
            break;
        }
        return 0;
    }
    
    static struct file_operations pwm_ops = {
        .owner = THIS_MODULE,
        .open  = ops_pwm_open,
        .release = ops_pwm_close,
        .unlocked_ioctl = ops_pwm_ioctl,
    };
    
    static struct miscdevice pwm_misc_dev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name  = DEVICE_NAME,
        .fops  = &pwm_ops,
    };
    
    static int __init iTop4412_pwm_dev_init(void)
    {
        int ret;
        gpio_free(PWM3_GPIO);
    
        ret = gpio_request(PWM3_GPIO, DEVICE_NAME);
        if(ret) {
                    printk(KERN_EMERG "request GPIO %d for pwm failed
    ", PWM3_GPIO);
                    return ret;
        }
    
            gpio_set_value(PWM3_GPIO, 0);
            s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);
    
            pwm4buzzer = pwm_request(PWM3_ID, DEVICE_NAME);
            if (IS_ERR(pwm4buzzer)) {
                    printk(KERN_EMERG "request pwm %d for %s failed
    ", PWM3_ID, DEVICE_NAME);
                    return -ENODEV;
            }
        pwm_stop();
    
        sema_init(&lock, 1);
        ret = misc_register(&pwm_misc_dev);
            if(ret < 0) {
                    gpio_free(BUZZER_PMW_GPIO);
                    pwm_free(pwm4buzzer);
                    misc_deregister(&pwm_misc_dev);
            }
    
        printk(KERN_EMERG "	initialized
    ");
    
        return ret;
    }
    
    static void __exit iTop4412_pwm_dev_exit(void)
    {
        gpio_free(BUZZER_PMW_GPIO);
            pwm_free(pwm4buzzer);
        misc_deregister(&pwm_misc_dev);
    
        printk(KERN_EMERG "	exit
    ");
        return;
    }
    
    module_init(iTop4412_pwm_dev_init);
    module_exit(iTop4412_pwm_dev_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Chen Tuo");
    MODULE_DESCRIPTION("Exynos4 PWM Driver");
    my_pwm3.c

    然后是应用程序:

    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <stdlib.h>
    #include <sys/ioctl.h>
    
    #define PWM2_NAME "/dev/my_pwm3_dev"
    
    #define PWM_MAGIC 'p'
    #define PWM_MAX_NR 3
    
    #define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
    #define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
    #define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)
    
    int fd = -1;
    
    void open_pwm1(void);
    void close_pwm1(void);
    void set_pwm_freq(int freq);
    void set_pwm_duty(int duty);
    void stop_pwm(void);
    
    void open_pwm1(void)
    {
        fd = open(PWM2_NAME, O_RDWR);
        if(fd < 0) {
            perror("open pwm1 device");
            exit(1);
        }
    
    //    atexit(close_pwm1);
    }
    
    void close_pwm1(void)
    {
        if(fd >= 0) {
            ioctl(fd, PWM_IOCTL_STOP);
            close(fd);
            fd = -1;
        }
    }
    
    void set_pwm_freq(int freq)
    {
        int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, &freq);
        if(ret < 0) {
            perror("set the frequency of the buzzer");
            exit(1);
        }
    }
    
    void set_pwm_duty(int duty)
    {
        int ret = ioctl(fd, PWM_IOCTL_SET_DUTY, &duty);
        if(ret < 0) {
            perror("set the duty of the pwm");
            exit(1);
        }
    }
    
    void stop_pwm(void)
    {
        int ret = ioctl(fd, PWM_IOCTL_STOP);
        if(ret < 0) {
            perror("Stop the buzzer");
            exit(1);
        }
    }
    
    int main(int argc, char *argv[])
    {
        int freq = 1000;
    
        open_pwm1();
        stop_pwm();
        if(argc < 3) {
            printf("usage:%s [cmd] [arg]
    ", argv[0]);
            printf("	stop:%s [0] [0] 
    ",argv[0]);
            printf("	set freq:%s [1] [arg]
    ", argv[0]);
            printf("	set duty:%s [2] [arg]
    ", argv[0]);
        }
            switch(atoi(argv[1]))
            {
            case 2:
                    set_pwm_duty(atoi(argv[2]));
            break;
            case 1:
                    set_pwm_freq(atoi(argv[2]));
                    break;
        case 0:
            default:
                    stop_pwm();
                    return -1;
            }
    
            return 0;
    }
    my_pwm3_app.c

    最后是Makefile:

    TARGET_NAME = my_pwm3
    #TARGET_NAME = example_pwm
    APP1_NAME = my_pwm3_app
    #APP2_NAME = open_atomic_int_two
    obj-m += $(TARGET_NAME).o
    
    KDIR := /home/topeet/chen/kernel-3.0/iTop4412_Kernel_3.0
    
    PWD ?= $(shell pwd)
    
    all:app1
            make -C $(KDIR) M=$(PWD) modules
    app1:
            arm-none-linux-gnueabi-gcc $(APP1_NAME).c -o $(APP1_NAME) -static
    #app2:
    #       arm-none-linux-gnueabi-gcc $(APP2_NAME).c -o $(APP2_NAME) -static
    
    clean:
            rm -rf *.o *.ko *.mod.c *.symvers *.order 
            .$(TARGET_NAME)* $(APP1_NAME) $(APP2_NAME)
    Makefile

    二、4412 I2C_SDA7和I2C_SCL7

    注释平台文件中的代码:

    //  s3c_i2c7_set_platdata(NULL);
    //  i2c_register_board_info(7, i2c_devs7, ARRAY_SIZE(i2c_devs7));

    和这个

    //  &s3c_device_i2c7,

    然后make menuconfig

    >>Device Drivers>>Input device support>>Touchscreens【】取消选择

    三、尝试编写控制PWM波形的驱动和应用程序

    my_pwm3.c(驱动)

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/platform_device.h>
    #include <linux/fb.h>
    #include <linux/backlight.h>
    #include <linux/err.h>
    #include <linux/pwm.h>
    #include <linux/slab.h>
    #include <linux/miscdevice.h>
    #include <linux/delay.h>
    #include <linux/gpio.h>
    #include <mach/gpio.h>
    #include <plat/gpio-cfg.h>
    #include <linux/ioctl.h>
    #include <asm-generic/uaccess.h>
    
    #define DEVICE_NAME "my_pwm3_dev"
    #define DRIVER_NAME "my_pwm3_drv"
    
    #define PWM_MAGIC 'p'
    #define PWM_MAX_NR 3
    
    #define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
    #define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
    #define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)
    
    #define NS_IN_1HZ                (1000000000UL)
    
    #define BUZZER_PWM_ID            0
    #define PWM1_ID                    1
    #define PWM2_ID                 2
    #define PWM3_ID                 3
    
    
    #define BUZZER_PMW_GPIO EXYNOS4_GPD0(0)
    #define PWM1_GPIO         EXYNOS4_GPD0(1)
    #define PWM2_GPIO       EXYNOS4_GPD0(2)
    #define PWM3_GPIO       EXYNOS4_GPD0(3)
    
    static struct pwm_device *pwm4buzzer;
    static struct semaphore lock;
    static int period_ns = 1000;
    static unsigned long freq = 50;
    static unsigned long duty = 2;
    
    static void pwm_set_freq(void)
    {
        //配置周期
        period_ns = NS_IN_1HZ / freq;
        //配置占空比
        if(duty < 2)
            duty = 2;
        pwm_disable(pwm4buzzer);
        pwm_config(pwm4buzzer, period_ns / duty, period_ns);
        pwm_enable(pwm4buzzer);
        //配置相应的GPIO,蜂鸣器IO配置成PWM输出模式
        s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_SFN(2));
    }
    
    static void pwm_stop(void)
    {
        s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);
    
        pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
        pwm_disable(pwm4buzzer);
    }
    
    static int ops_pwm_open(struct inode *inode, struct file *file)
    {
        if(!down_trylock(&lock))
            return 0;
        else
            return -EBUSY;
    }
    
    static int ops_pwm_close(struct inode *inode, struct file *file)
    {
        up(&lock);
        return 0;
    }
    
    static long ops_pwm_ioctl(struct file *filep, unsigned int cmd,
            unsigned long arg)
    {
        if(_IOC_TYPE(cmd)!=PWM_MAGIC) return -EINVAL;
        if(_IOC_NR(cmd) > PWM_MAX_NR) return -EINVAL;
    
        switch(cmd) {
        case PWM_IOCTL_SET_FREQ:
            if(arg == 0)
                return -EINVAL;
            get_user(freq, (unsigned long __user *)arg);
            printk(KERN_EMERG "freq is %ld
    ", freq);
            pwm_set_freq();
            break;
        case PWM_IOCTL_STOP:
            pwm_stop();
            break;
        case PWM_IOCTL_SET_DUTY:
            get_user(duty, (unsigned long __user *)arg);
            printk(KERN_EMERG "duty is %ld
    ", duty);
            pwm_set_freq();
            break;
        default:
            pwm_stop();
            break;
        }
        return 0;
    }
    
    static struct file_operations pwm_ops = {
        .owner = THIS_MODULE,
        .open  = ops_pwm_open,
        .release = ops_pwm_close,
        .unlocked_ioctl = ops_pwm_ioctl,
    };
    
    static struct miscdevice pwm_misc_dev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name  = DEVICE_NAME,
        .fops  = &pwm_ops,
    };
    
    static int __init iTop4412_pwm_dev_init(void)
    {
        int ret;
        gpio_free(PWM3_GPIO);
    
        ret = gpio_request(PWM3_GPIO, DEVICE_NAME);
        if(ret) {
            printk(KERN_EMERG "request GPIO %d for pwm failed
    ", PWM3_GPIO);
            return ret;
        }
    
        gpio_set_value(PWM3_GPIO, 0);
        s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);
    
        pwm4buzzer = pwm_request(PWM3_ID, DEVICE_NAME);
        if (IS_ERR(pwm4buzzer)) {
            printk(KERN_EMERG "request pwm %d for %s failed
    ", PWM3_ID, DEVICE_NAME);
            return -ENODEV;
        }
        pwm_stop();
    
        sema_init(&lock, 1);
        ret = misc_register(&pwm_misc_dev);
        if(ret < 0) {
            gpio_free(BUZZER_PMW_GPIO);
            pwm_free(pwm4buzzer);
            misc_deregister(&pwm_misc_dev);
        }
    
        printk(KERN_EMERG "	initialized
    ");
    
        return ret;
    }
    
    static void __exit iTop4412_pwm_dev_exit(void)
    {
        gpio_free(BUZZER_PMW_GPIO);
        pwm_free(pwm4buzzer);
        misc_deregister(&pwm_misc_dev);
        
        printk(KERN_EMERG "	exit
    ");
        return;
    }
    
    module_init(iTop4412_pwm_dev_init);
    module_exit(iTop4412_pwm_dev_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Chen Tuo");
    MODULE_DESCRIPTION("Exynos4 PWM Driver");
    my_pwm3.c

    my_pwm3_app.c

    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <stdlib.h>
    #include <sys/ioctl.h>
    
    #define PWM2_NAME "/dev/my_pwm3_dev"
    
    #define PWM_MAGIC 'p'
    #define PWM_MAX_NR 3
    
    #define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
    #define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
    #define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)
    
    int fd = -1;
    
    void open_pwm1(void);
    void close_pwm1(void);
    void set_pwm_freq(int freq);
    void set_pwm_duty(int duty);
    void stop_pwm(void);
    
    void open_pwm1(void)
    {
        fd = open(PWM2_NAME, O_RDWR);
        if(fd < 0) {
            perror("open pwm1 device");
            exit(1);
        }
    
    //    atexit(close_pwm1);
    }
    
    void close_pwm1(void)
    {
        if(fd >= 0) {
            ioctl(fd, PWM_IOCTL_STOP);
            close(fd);
            fd = -1;
        }
    }
    
    void set_pwm_freq(int freq)
    {
        int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, &freq);
        if(ret < 0) {
            perror("set the frequency of the buzzer");
            exit(1);
        }
    }
    
    void set_pwm_duty(int duty)
    {
        int ret = ioctl(fd, PWM_IOCTL_SET_DUTY, &duty);
        if(ret < 0) {
            perror("set the duty of the pwm");
            exit(1);
        }
    }
    
    void stop_pwm(void)
    {
        int ret = ioctl(fd, PWM_IOCTL_STOP);
        if(ret < 0) {
            perror("Stop the buzzer");
            exit(1);
        }
    }
    
    int main(int argc, char *argv[])
    {
        int freq = 1000;
    
        open_pwm1();
        stop_pwm();
        if(argc < 3) {
            printf("usage:%s [cmd] [arg]
    ", argv[0]);
            printf("	stop:%s [0] [0] 
    ",argv[0]);
            printf("	set freq:%s [1] [arg]
    ", argv[0]);
            printf("	set duty:%s [2] [arg]
    ", argv[0]);
        }
        switch(atoi(argv[1]))
        {
        case 2:
            set_pwm_duty(atoi(argv[2]));
            break;
        case 1:
            set_pwm_freq(atoi(argv[2]));
            break;
        case 0:
        default:
            stop_pwm();
            return -1;
        }
    
        return 0;
    }
    my_pwm3_app.c

    Makefile

    TARGET_NAME = my_pwm3
    #TARGET_NAME = example_pwm
    APP1_NAME = my_pwm3_app
    #APP2_NAME = open_atomic_int_two
    obj-m += $(TARGET_NAME).o
    
    KDIR := /home/topeet/chen/kernel-3.0/iTop4412_Kernel_3.0
    
    PWD ?= $(shell pwd)
    
    all:app1
            make -C $(KDIR) M=$(PWD) modules
    app1:
            arm-none-linux-gnueabi-gcc $(APP1_NAME).c -o $(APP1_NAME) -static
    #app2:
    #       arm-none-linux-gnueabi-gcc $(APP2_NAME).c -o $(APP2_NAME) -static
    
    clean:
            rm -rf *.o *.ko *.mod.c *.symvers *.order 
            .$(TARGET_NAME)* $(APP1_NAME) $(APP2_NAME)
    Makfile

    总结:内核接收ioctl的信息时需要使用特定的函数进行保护,防止被乱七八糟的传入数据。

  • 相关阅读:
    安装一些好用的工具
    转:通过快键强制关闭 Ubuntu 上无响应的程序
    同步cm10.1源码时出现的一些错误的解决办法。
    repo sync的介绍翻译
    配置grub解决ubuntu12.04不能保存亮度和调节的问题
    给fcitx加上云拼音库
    自己安装配置ubuntu12.04过程(内容丰富)
    关于repo sync -j*的含义的猜测
    同步cm10.1的时候发生同步错误不能找到github上的文件
    Element-ui tree组件自定义节点使用方法
  • 原文地址:https://www.cnblogs.com/ch122633/p/9602679.html
Copyright © 2011-2022 走看看