Buzzer driver under Linux design

 

Embedded systems development technology

 

____________________________________________________ 1. Introduction 3

1.1 Overview ______________________________________________________ 3

1.2 design content __________________________________________________ 4

2. set up a development environment __________________________________________ 4

2.1Redhat installation ______________________________________________ 4

2.2 mounting arm-linux-gcc cross compiler _______________________________ 9

2.3 to install and compile linux-2.6.29-mini2440-20090708 core 9 ________________

3. The character device driver knowledge ____________________________________ 9

3.1 module mechanism __________________________________________________ 9

3.2 The basic steps to develop a character device _____________________________________ 10

3.3 major and minor number 11 _______________________________________

3.4 implements a character driver _________________________________________ 12

4. buzzer principle _____________________________________________ 14

Kind and works buzzer ___________________________________ 14 4.1

4.2 development board schematics buzzer analysis _________________________________ 15

4.3GPB0 parameters ________________________________________________ 15

The overall design _______________________________________________ 16

5.1 design ideas _________________________________________________ 16

5.2 Design Procedure _________________________________________________ 16

6. The driver 17 and test procedures ________________________________________

6.1beep.c____________________________________________________ 17

6.2beep_tset.c________________________________________________ 21

7. operating results and screenshots _________________________________________ 22

Comprehensive design summary and thinking ______________________________________ 25

 

 

 

                     1. Introduction

1.1 Overview

linux drive is essentially a software program, in a case where the upper layer software without hardware features to understand, communicate through the interface, and the computer hardware drivers provided.

System calls are the interface between the kernel and applications, and the driver is the interface between the kernel and the hardware, which is a bridge between the kernel and the hardware. It shields the details of the hardware for the application, so the application view, the hardware device is a device file, the application can operate like an ordinary file to operate on hardware devices.

linux driver is part of the kernel, the system manages the device controller and the corresponding equipment. It is mainly the so several functions: initialization and releasing equipment; transmitting data to and read data from the hardware hardware; error detecting and processing device appears.

In general, a driver may manage one type of apparatus. For example, they belong to different U disk mass storage device, we do not need to write drivers for each U-disk, but only one driver can manage all of these mass storage devices.

To help us add a variety of drivers to support different hardware, the kernel abstract a lot of hierarchy, these hierarchies are upper linux device driver. They abstract various driver interface, the drive only need to fill out the appropriate callback function, you can easily add new drivers to the kernel.

Generally, linux drivers into three categories, that is, the block device drivers, and network device driver character device driver. Write cache block device has to support, and the device must be able to block random access. Block device driver is mainly used for a magnetic disk drive.

And the character device I / O operations by caching no. Character devices operating in byte basis, but not to say that can only perform one byte operations. For example, a character device we can exchange large amounts of data through mmap once. Character device is relatively simple and flexible.

1.2 Design Content

The design is simple character device driver design, driver design is based on the mini2440 buzzer.

                    2. The development environment to build

 

2.1Redhat installation

Create a virtual machine: Click the menu bar File-> New-> Virtual machine. Click Next.

Select the Typical option.

Select the Linux Red Hat Linux

Fill in the name and address of the virtual machine storage.

 

Select the disk size

2.2 mounting arm-linux-gcc cross compiler

     Copy the arm-linux-gcc-4.3.2.tgz to the root directory of the virtual machine

Unzip the file: tar zxvf arm-linux-gcc-4.3.2.tgz

在bash_profile里添加路径:gedit ~/.bash_profiel

路径 /root/usr/local/arm/4.3.2/bin

source ~/.bash_profile 使更改生效

 

2.3安装及编译linux-2.6.29-mini2440-20090708内核

复制内核到root目录下

解压内核文件 tar zxvf linux-2.6.29-mini2440-20090708.tgz

使内核文件生效:cp config_mini2440_n35 .config

使用make命令完成编译

                  3.字符设备驱动相关知识

3.1模块机制

Linux提供了机制被称为模块(Module)的机制

 

提供了对许多模块支持, 包括但不限于, 设备驱动

 

每个模块由目标代码组成( 没有连接成一个完整可执行程序 )

insmod 将模块动态加载到正在运行内核

rmmod 程序移除模块

 

Linux内核模块的程序结构

 

  1. module_init()---模块加载函数(必须)

通过insmod或modprobe命令加载内核模块时,模块的加载函数  会自动被内核执行,完成模块的相关初始化工作

 

  1. module_exit()---模块卸载函数(必须)

当通过rmmod命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块装载函数相反的功能

  1. MODULE_LICENSE()---模块许可证声明(必须)

模块许可证(LICENSE)声明描述内核模块的许可权限

如果不声明LICENSE,模块被加载时,将收到内核被污染(kernel tainted)的警告

 

 

  1. module_param()---模块参数(可选)

模块参数是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量。

  1. EXPORT_SYMBOL()---模块导出符号(可选)

内核模块可以导出符号(symbol,对应于函数或变量)到内核

其他模块可以使用本模块中的变量或函数

 

  1. 其他一些声明MODULE_XXXXX()---模块声明(可选)

模块加载函数

static int   __init     initialization_function(void)

{

  /* 初始化代码 */

}

module_init(initialization_function);

模块卸载函数

  static void     __exit   cleanup_function(void)

  {

        /* 释放资源 */

  }

  module_exit(cleanup_function);

 

 

3.2字符设备开发基本步骤

 

  1. 确定主设备号和次设备号

 

  1. 实现字符驱动程序

实现file_operations结构体

实现初始化函数,注册字符设备

实现销毁函数,释放字符设备

 

  1. 创建设备文件节点

 

3.3主设备号和次设备号

 

  • 主设备号是内核识别一个设备的标识。

整数(占12bits),范围从0到4095,通常使用1到255

 

  • 次设备号由内核使用,用于正确确定设备文件所指的设备。

整数(占20bits),范围从0到1048575,一般使用0到255

 

  • 设备编号的内部表达

dev_t类型(32位):

用来保存设备编号(包括主设备号(12位)和次设备号(20位))

从dev_t获得主设备号和次设备号:

MAJOR(dev_t);

MINOR(dev_t);

将主设备号和次设备号转换成dev_t类型:

MKDEV(int major,int minor);

  • 分配主设备号

手工分配主设备号:找一个内核没有使用的主设备号来使用。

#include <linux/fs.h>

int register_chrdev_region( dev_t first,     unsigned int count,    char *name );

  • 动态分配主设备号:

#include <linux/fs.h>

int  alloc_chrdev_resion(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

  • 释放设备号

void  unregister_chrdev_region(dev_t first, unsigned int count);

3.4实现字符驱动程序

  1. cdev 结构体

struct cdev

 {

   struct kobject kobj;              /* 内嵌的kobject 对象 */

   struct module *owner;         /*所属模块*/

   struct file_operations *ops;  /*文件操作结构体*/

   struct list_head list;

   dev_t dev;                           /*设备号*/

   unsigned int count;

 };

  1. file_operations 结构体

 

字符驱动和内核的接口:

在include/linux/fs.h定义

 

字符驱动只要实现一个file_operations结构体

 

并注册到内核中,内核就有了操作此设备的能力。

  1. file_operations的主要成员:

struct module *owner: 指向模块自身

open:打开设备

release:关闭设备

read:从设备上读数据

write:向设备上写数据

ioctl:I/O控制函数

llseek:定位读写指针

mmap:映射设备空间到进程的地址空间

  1. ioctl函数

为设备驱动程序执行“命令”提供了一个特有的入口点

用来设置或者读取设备的属性信息。

int    ioctl (struct inode *inode, struct file *filp,

             unsigned int cmd, unsigned long arg);

  1. cmd 参数的定义

不推荐用0x1,0x2,0x3之类的值

Linux对ioctl()的cmd参数有特殊的定义

 

构造命令编号的宏:

_IO(type,nr)用于构造无参数的命令编号;

_IOR(type,nr,datatype)用于构造从驱动程序中读取数据的命令编号;

_IOW(type,nr,datatype)用于写入数据的命令;

_IOWR(type,nr,datatype)用于双向传输。

type和number位字段通过参数传入,而size位字段通过对datatype参数取sizeof获得。

  1. Ioctl函数模板

int xxx_ioctl( struct inode *inode, struct f ile *filp, unsigned int cmd,

                      unsigned long arg)

 {

   ...

   switch (cmd)

   {

      case XXX_CMD1:

      ...

      break;

      case XXX_CMD2:

      ...

      break;

      default:  ///*不能支持的命令 */

      return - ENOTTY;

   }

   return 0;

 }

 

3.5字符设备驱动结构

                       4.蜂鸣器原理                   

4.1蜂鸣器的种类和工作原理

   蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。

   压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。有的压电式蜂鸣器外壳上还装有发光二极管。多谐振荡器由晶体管或集成电路构成。当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。

   电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。

   有源蜂鸣器和无源蜂鸣器的区别:这个“源”字是不是指电源,而是指震荡源,即有源蜂鸣器内有振荡源而无源蜂鸣器内部没有振荡源。有振荡源的通电就可以发声,没有振荡源的需要脉冲信号驱动才能发声。

4.2开发板上蜂鸣器原理图分析

 

由原理图可以得知,蜂鸣器是通过GPB0 IO口使用PWM信号驱动工作的,而GPB0口是一个复用的IO口,要使用它得先把他设置成TOUT0 PWM输出模式。

4.3GPB0参数

 

 

 

                        5.总体设计

5.1设计思路

 Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载:

(1)直接编译进Linux内核,随同Linux启动时加载;

(2)编译成一个可加载和删除的模块,使用insmod加载(modprobe和insmod命令类似,但依赖于相关的配置文件),rmmod删除。这种方式控制了内核的大小,而模块一旦被插入内核,它就和内核其他部分一样。

  这次的蜂鸣器驱动就采用动态模块加载的方式

5.2设计步骤

  • 编写简单的字符设别驱动程序框架
  • 编写控制蜂鸣器控制开关函数
  • 编译模块,生成.ko

  

  • 编写用户层测试程序
  • 编译用户层测试程序,生成可执行程序beep_test
  • 将生成的.ko 模块和应用层测试程序 beep_test 下载到目标板
  • 用 insmod 装载模块
  • 创建设备节点

   mknod /dev/beep c 253 0

  • 运行用户层测试程序 beep_test

#./beep_test

如果你的 beep_test 的属性不是可执行的,可以用 chmod 777 beep_test  将其设置成可执行

程序。

  1. 驱动及测试程序

6.1beep.c

#include<linux/module.h>

#include<linux/types.h>

#include<linux/fs.h>

#include<linux/errno.h>

#include<linux/mm.h>

#include<linux/sched.h>

#include<linux/init.h>

#include<linux/cdev.h>

#include<linux/io.h>

#include<asm/system.h>

#include<asm/uaccess.h>

#include<asm/io.h>

#include <asm/irq.h>

#include <linux/slab.h>

#include <linux/ioport.h>

#include <mach/hardware.h>

#include <mach/gpio-fns.h>

#include <asm/irq.h>

#include <linux/init.h>

#include <linux/gpio.h>

#include <plat/devs.h>

#include <linux/types.h>

#include <linux/interrupt.h>

#include <linux/list.h>

#include <linux/timer.h>

#include <linux/init.h>

#include <linux/gpio.h>

#include <linux/sysdev.h>

#include <linux/platform_device.h>

 

 

#include <asm/mach/arch.h>

#include <asm/mach/map.h>

#include <asm/mach/irq.h>

 

#include <asm/mach-types.h>

#include <mach/hardware.h>

#include <asm/irq.h>

#include <mach/regs-gpio.h>

#include <plat/pm.h>

 

 

#define BEEP_MAJOR 201

#define BEEP_START_CMD 0x0

#define BEEP_STOP_CMD 0x1

 

static int beep_major=BEEP_MAJOR;

 

 

static struct cdev BeepDevs;

 

static int beep_open(struct inode *inode,struct file *filp)

{

      return 0;

}

 

static int beep_relesae(struct inode *inode,struct file *filp)

{

      return 0;

}

 

static void beep_stop(void)

{

     

s3c2410_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPIO_OUTPUT);

      s3c2410_gpio_setpin(S3C2410_GPB(0),0);

      printk("stop\n");

}

 

static void beep_start(void)

{

     

s3c2410_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPIO_OUTPUT);

      s3c2410_gpio_setpin(S3C2410_GPB(0),1);

      printk("start\n");

}

 

static int beep_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)

{

      switch(cmd)

      {

            case BEEP_START_CMD:

                  printk("beep_strat\n");

                  beep_start();

                  break;

            case BEEP_STOP_CMD:

                  printk("beep_stop\n");

                  beep_stop();

                  break;

            default:

                  printk("default\n");

                  break;

      }

 

      return 0;   

}

 

static struct file_operations beep_remap_ops={

      .owner = THIS_MODULE,

      .open =beep_open,

      .release = beep_relesae,

      .ioctl = beep_ioctl,

};

 

static void beep_setup_cdev(struct cdev *dev, int minor,struct file_operations *fops)

{

      int err,devno = MKDEV(beep_major,minor);

 

      cdev_init(dev,fops);

      dev->owner = THIS_MODULE;

      dev->ops = fops;

      err = cdev_add(dev,devno,1);

      if(err)

      {

            printk("error %d adding beep %d \n",err,minor);

      }

}

 

static int __init  beep_init(void)

{

      int result;

      dev_t dev=MKDEV(beep_major,0);

 

      if(beep_major)

      {

            result= register_chrdev_region(dev,1,"beep");

      }

      else

      {

            result=alloc_chrdev_region(&dev,0,1,"beep");

            beep_major=MAJOR(dev);

      }

 

      if(result<0)

      {

            printk("beep: unable to get major %d \n",beep_major);

            return result;

      }

 

      if(beep_major==0)

      {

            beep_major=result;

      }

     

 

      beep_setup_cdev(&BeepDevs,0,&beep_remap_ops);

      printk("beep devices installed,with major %d",beep_major);

      return 0;

}

 

static void __exit beep_exit()

{

      cdev_del(&BeepDevs);

      unregister_chrdev_region(MKDEV(beep_major,0),1);

      printk("beep device uninstalled\n");

}

 

 

MODULE_AUTHOR("xdq");

MODULE_LICENSE("GPL");

 

module_init(beep_init);

module_exit(beep_exit);

 

6.2beep_tset.c

#include<stdio.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdlib.h>

 

int main()

{

      int dev_fd;

      char c;

      dev_fd=open("/dev/beep",O_WRONLY|O_NONBLOCK);

      if(dev_fd == -1)

      {

            printf("con not flie\n");

            exit(0);

      }

 

      ioctl(dev_fd,0x0,0);

 

      getchar();

      getchar();

 

      ioctl(dev_fd,0x1,0);

     

      getchar();

      getchar();

 

      close(dev_fd);

      return 0;

}

 

                   7.运行结果及截图

 

 

传输beep.ko,ls命令查看文件。

传输beep_test可执行文件。使用./beep_test命令运行测试程序

beep_stat,蜂鸣器响了,按下键盘一键,beep_stop,蜂鸣器停止

Guess you like

Origin blog.csdn.net/qq_40636929/article/details/91412641