• 〖Linux〗OK6410a蜂鸣器的驱动程序编写全程实录


    最近在看一本书,受益匪浅,作者是李宁,下边是编写本次蜂鸣器的全程实录:

    1. 了解开发板中的蜂鸣器

     1) 查看蜂鸣器buzzer在底板中的管脚信息

     2) 查看蜂鸣器在总线中的信息

     3) 翻看S3C6410芯片手册,查看GPF15相关信息

    2. 在了解了开发板中蜂鸣器之后,编写代码对它进行控制。

     由于蜂鸣器是通过PWM(脉冲宽度调制)进行开关控制的,故也称为PWM。

     1) 编写pwm.c(包含Linux驱动模块的主要模型代码)

    #include "pwm_fun.h"
    
    static struct semaphore lock;                   /* 创建信号量*/
    
    //文件打开时,自动操作此函数,使用信号量控制其访问
    static int s3c6410_pwm_open(struct inode *inode, struct file *file){
        if (!down_trylock(&lock))                   /* 使用信号量控制只能由一个进程打开 */
        {
            return 0;
        }
        else{
            return -EBUSY;
        }
    }
    
    //文件关闭时,自动操作此函数,使用信号量控制其访问
    static int s3c6410_pwm_close(struct inode *inode, struct file *file){
        up(&lock);                                  /* 释放信号量 */
        return 0;
    }
    
    //文件中关于ioctl的操作
    static long s3c6410_pwm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg){
    
        switch ( cmd ) {
            case PWM_IOCTL_START:    
                pwm_start();
                break;
    
            case PWM_IOCTL_STOP:    
                pwm_stop();
                break;
    
            default:    
                break;
        }                /* -----  end switch  ----- */
    
        return 0;
    }
    
    //文件操作的指针
    static struct file_operations dev_fops = {
        .owner = THIS_MODULE,
        .open = s3c6410_pwm_open,
        .release = s3c6410_pwm_close,
        .unlocked_ioctl = s3c6410_pwm_ioctl,
    };
    
    //设备的属性
    static struct miscdevice misc = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &dev_fops,
    };
    
    //驱动的入口函数
    static int __init dev_init(void){
        int ret; 
        init_MUTEX(&lock);                          /* 初始化信号量 */
        ret = misc_register(&misc);
        printk(DEVICE_NAME"	initialized
    ");
        return ret;
    }
    
    //驱动的退出函数
    static void __exit dev_exit(void){
        misc_deregister(&misc);
        printk(DEVICE_NAME"	exited
    ");
    }
    
    module_init(dev_init);
    module_exit(dev_exit);

     2) 编写pwm_fun.c(包含对蜂鸣器控制的主要代码)

    #include "pwm_fun.h"
    
    void pwm_start(void){
        unsigned int tmp;
        tmp = ioread32(S3C64XX_GPFCON);
        tmp  &= ~(0x3U<<30);                        /* 最高两位清零,保留其他位 */
        tmp |= (0x2U<<30);                          /* 最高两位设置为10,蜂鸣器发出尖叫声 */
        iowrite32(tmp, S3C64XX_GPFCON);
    }
    
    void pwm_stop(void){
        unsigned tmp;
        tmp = ioread32(S3C64XX_GPFCON);
        tmp &= ~(0x3U<<30);                         /* 最高两位清零,蜂鸣器停止尖叫 */
        iowrite32(tmp, S3C64XX_GPFCON);
    }

     3) 编写pwm_fun.h(包含一些必须的头文件及宏定义信息)

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <asm/io.h>
    #include <linux/interrupt.h>
    #include <linux/device.h>
    #include <asm/uaccess.h>
    #include <linux/miscdevice.h>
    #include <mach/map.h>
    #include <mach/regs-clock.h>
    #include <mach/regs-gpio.h> 
    #include <mach/gpio-bank-f.h>
    #include <mach/gpio-bank-k.h>
    
    #define DEVICE_NAME "pwm_dev"
    #define PWM_IOCTL_START 1
    #define PWM_IOCTL_STOP 0
    
    extern void pwm_start(void);
    extern void pwm_stop(void);

     4) 编写Makefile文件(使编译过程自动完成)

    obj-m := pwm_driver.o
    pwm_driver-objs := pwm.o pwm_fun.o
    PWD := $(shell pwd)
    CROSS_COMPILE ?= arm-none-linux-gnueabi-
    CC := $(CROSS_COMPILE)gcc
    CFLAGS += -static
    KPATH := /media/Source/Forlinx/android2.3_kernel_v1.01
    all: ioctl
        make -C $(KPATH) M=$(PWD) modules
    ioctl: ioctl.c
        $(CC) $(CFLAGS) $^ -o $@
    clean:
        rm -rf *.o *.ko *.mod.c Module.* modules.* ioctl

     5) 编写测试程序ioctl(用于对驱动程序的测试)

    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    
    /* 
     * ===  FUNCTION  ======================================================================
     *         Name:  main
     *  Description:  对驱动程序进行测试
     * =====================================================================================
     */
    int main ( int argc, char *argv[] )
    {
        int file_handler = 0;
        int cmd = 0;
        int arg = 0;
        if (argc < 4)
        {
            printf("Usage: ioctl <DEVICE_NAME> <cmd> <arg>
    ");
            return EXIT_FAILURE;
        }
        cmd = atoi(argv[2]);
        arg = atoi(argv[3]);
        printf("dev:%s
    ", argv[1]);
        printf("cmd:%d
    ", cmd);
        printf("arg:%d
    ", arg);
        file_handler = open(argv[1], 0);
        if (file_handler<0)
        {
            printf("open %s failure.
    ", argv[1]);
        }
        ioctl(file_handler, cmd, arg);
        close(file_handler);
        return EXIT_SUCCESS;

    3. 编写好源代码程序之后,交叉编译,上传至OK6410A开发板,进行测试

      1) 配置好交叉编译工具链arm-none-linux-gnueabi-gcc之后,在终端输入make即可自动完成编译

      2) OK6410A(Android2.3.4操作系统)通过USB线连接至PC端,通过adb上传至开发板:

        adb push pwm_driver.ko /tmp/pwm_driver.ko

        adb push ioctl /tmp/ioctl

      3) 通过adb shell打开并控制OK6410A开发板,输入命令安装驱动模块:

        adb shell

        insmod /tmp/pwm_driver.ko

      4) 测试蜂鸣器驱动程序

        /tmp/ioctl /dev/pwm_dev 1 0 #打开蜂鸣器

        /tmp/ioctl /dev/pwm_dev 0 0 #关闭蜂鸣器

  • 相关阅读:
    nodejs + mongodb
    实习踩坑
    jQuery获取点击对象的父级
    python正则表达式
    python文件基础IO,OS
    python模块
    python时间和日期
    python number
    python循环
    Vue2.0 【第一季】第6节 v-model指令
  • 原文地址:https://www.cnblogs.com/scue/p/3477730.html
Copyright © 2020-2023  润新知