S3C6410的PWM驱动实例

发布者:CuriousObserver最新更新时间:2024-09-18 来源: cnblogs关键字:S3C6410  PWM驱动  蜂鸣器 手机看文章 扫描二维码
随时随地手机看文章

我们使用PWM来控制蜂鸣器,主要是两种功能,一是使能蜂鸣器,并设置其频率;二是禁止蜂鸣器。这些操作均可通过ioctl来完成。所以在pwm的设备驱动中,主要也就是ioctl这个函数。


首先,我们要定义两个命令,用在ioctl函数中的switch语句中,至于怎么来定义这两个命令呢?其实简单的做法,我们可以将其定义为两个不同的常量,能用在switch语句中即可,但是这样会造成一定的问题。例如,其他的设备也有支持设个命令的,例如串口支持设置波特率等,很有可能在写代码时不小心,写成了串口,结果调用的时候,驱动没报错,因为串口也支持这个命令,解决办法就是不同的设备支持不同的命令号,及时目前有一部分驱动依旧是使用之前的那种简单定义命令号的方式,但是我们要严格要求自己。


那怎么样才能使得自己定义的命令号不和内核已存在的命令号冲突呢?内核定义了几个简单的宏,使得我们使用这些宏来定义自己的命令号就肯定没问题了。


在include/asm/ioctl.h文件里,这些宏是:

/* used to create numbers */

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)

#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))

#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))

#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))


其实主要使用的就是上面四个,可以看到这个宏定义中还有一个_IOC宏定义,我们来看看是啥:

#define _IOC(dir,type,nr,size)

(((dir)  << _IOC_DIRSHIFT) |

((type) << _IOC_TYPESHIFT) |

((nr)   << _IOC_NRSHIFT) |

((size) << _IOC_SIZESHIFT)) 

       可以看到其实是对四个因素的结合,第一个是传输方向,第二个是幻数,第三个是序数,第四个是数据大小。

       首先是传输方向,以应用为中心考察,如果数据从驱动传输到应用,那么就是读取操作,如果数据从应用传输到驱动,那就是写入操作;

       再者是幻数(IMAGENUMBER),这个是可以自己定义的,有8bits宽,整个驱动都使用这个数字;

       然后就是序数,这个算得是幻数大类里面的小类了,因为一个ioctl里面一般不止一个命令,所以,这个主要是用来区别各个命令的,上面的幻数在各个命令你都是一样的。

       最后就是传输数据的大小,可以通过对参数使用sizeof运算符获取。

       下面来举个例子,在我们的pwm驱动里面有两个命令,一个是启动并设置频:PWM_START,另外一个是PWM_STOP。在这个过程中不涉及数据的传输,所以使用上面的第一个宏_IO(type, nr)。

       一个参数type是一个幻数,我们可以定义为3825:

      #define PWM_MAGIC

3825

      然后是定义命令序列号,这里有两个命令,序号我分别选为0和1,因此整个可以这样定义:

      #define PWM_START _IO(PWM_MAGIC, 0)

      #define PWM_STOP _IO(PWM_MAGIC, 1)

      有了这两个定义,我们就可以在switch中如下使用:

    switch(cmd)

    {

    case PWM_START:

    ...

    break;

    case PWM_STOP:

    ...

    break;

    default:

    ...

    }

    再来说说实现使能pwm输出控制蜂鸣器和禁止pwm输出,其实都是通过控制GPF14、15脚的功能。GPF14是PWM0,GPF15是PWM1.看你的开发板使用那一路PWM输出驱动蜂鸣器的。那么设置频率怎么实现呢?其实pwm是内部定时器的功能,我们只需要设置几个相关的特殊寄存器即可,这涉及都PWM内容,上一节有讲到哦,具体每个寄存器给什么值,这个看一下芯片手册,看一下上一篇博文就知道了,这里不再细说。

    接下来就看看一个pwm的驱动程序,通过上面的内容,我相信这个驱动一目了然,呵呵!对照上面内容看,收获更大。

    

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include

#include

#include


#include

#include

#include

#include


#define DEVICE_NAME     'pwm'


#define PWM_IOCTL_SET_FREQ 1

#define PWM_IOCTL_STOP 0


static struct semaphore lock;


/* freq:  pclk/50/16/65536 ~ pclk/50/16 

  * if pclk = 50MHz, freq is 1Hz to 62500Hz

  * human ear : 20Hz~ 20000Hz

  */

static void PWM_Set_Freq( unsigned long freq )

{

unsigned long tcon;

unsigned long tcnt;

unsigned long tcfg1;

unsigned long tcfg0;


struct clk *clk_p;

unsigned long pclk;


unsigned tmp;


tmp = readl(S3C64XX_GPFCON);

tmp &= ~(0x3U << 28);

tmp |=  (0x2U << 28);

writel(tmp, S3C64XX_GPFCON);


tcon = __raw_readl(S3C_TCON);

tcfg1 = __raw_readl(S3C_TCFG1);

tcfg0 = __raw_readl(S3C_TCFG0);


//prescaler = 50

tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;

tcfg0 |= (50 - 1); 


//mux = 1/16

tcfg1 &= ~S3C_TCFG1_MUX0_MASK;

tcfg1 |= S3C_TCFG1_MUX0_DIV16;


__raw_writel(tcfg1, S3C_TCFG1);

__raw_writel(tcfg0, S3C_TCFG0);


clk_p = clk_get(NULL, 'pclk');

pclk  = clk_get_rate(clk_p);

tcnt  = (pclk/50/16)/freq;

__raw_writel(tcnt, S3C_TCNTB(0));

__raw_writel(tcnt/2, S3C_TCMPB(0));

tcon &= ~0x1f;

tcon |= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0

__raw_writel(tcon, S3C_TCON);

tcon &= ~2; //clear manual update bit

__raw_writel(tcon, S3C_TCON);

}


void PWM_Stop( void )

{

unsigned tmp;

tmp = readl(S3C64XX_GPFCON);

tmp &= ~(0x3U << 28);

writel(tmp, S3C64XX_GPFCON);

}


static int s3c64xx_pwm_open(struct inode *inode, struct file *file)

{

if (!down_trylock(&lock))

return 0;

else

return -EBUSY;

}



static int s3c64xx_pwm_close(struct inode *inode, struct file *file)

{

up(&lock);

return 0;

}



static long s3c64xx_pwm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)

{

switch (cmd) {

case PWM_IOCTL_SET_FREQ:

if (arg == 0)

return -EINVAL;

PWM_Set_Freq(arg);

break;


case PWM_IOCTL_STOP:

default:

PWM_Stop();

break;

}


return 0;

}



static struct file_operations dev_fops = {

    .owner = THIS_MODULE,

    .open = s3c64xx_pwm_open,

    .release = s3c64xx_pwm_close, 

    .unlocked_ioctl = s3c64xx_pwm_ioctl,

};


static struct miscdevice misc = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &dev_fops,

};


static int __init dev_init(void)

{

int ret;


sema_init(&lock, 1);

ret = misc_register(&misc);


printk (DEVICE_NAME'tinitializedn');

    return ret;

}


static void __exit dev_exit(void)

{

misc_deregister(&misc);

}


module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE('GPL');

MODULE_AUTHOR('FriendlyARM Inc.');

MODULE_DESCRIPTION('S3C6410 PWM Driver');


关键字:S3C6410  PWM驱动  蜂鸣器 引用地址:S3C6410的PWM驱动实例

上一篇:【嵌入式开发】写入开发板Linux系统-模型S3C6410
下一篇:misc设备驱动模型及实例解析

推荐阅读最新更新时间:2024-11-11 17:49

wince6.0+s3c6410摄像头驱动修改
这段时间开发一个图像识别的项目,基于WinCE6.0+s3c6410 系统,使用友坚恒天的6410 开发板。该开发板带有OV9650 摄像头接 口,但存在一个最大的问题,是摄像头获取的图像太小,只能看到320*240 的图像,我需要1280*1024 的图像,所以只能修改。本想驱动能提供接 口,可以在应用程序中修改像素,但仔细分析驱动源代码发现,摄像头的像素是在驱动中设置死的,所以只能修改驱动。修改驱动的过程中走了很多弯路,不过今天 终于成功了,可以成功显示640*480 和1280*1024 的图像。 驱动中需要修改的文件主要有:setting.h ,OV9650_MODUAL.cpp, sensorformat.h, s3
[单片机]
APPWeb+PHP5+SQLite3在S3C6410上移植
我自己是移植Lighttpd+PHP+SQLite3的,由于忘了PHP怎么移植,所以就转别人的,免得以后再移植会忘记 原作者: hwwr112100 网址:http://blog.csdn.net/hwwr112100/article/details/8249294 相关支持库移植 主要包括libiconv、zlib以及加密服务组件matrixssll。 下载Embedthis提供的第三方工具包,采用git从GitHub获取packages软件包,命令如下。 gitclone http://github.com/embedthis/packages 如果下载失败,可以在直接在 https://github.com
[单片机]
APPWeb+PHP5+SQLite3在<font color='red'>S3C6410</font>上移植
STM32学习第一周之 按键矩阵
添加一个矩阵键盘,STM32 检测到不同按键按下,实现不同功能: 键 1-7 按下,依次点亮红、绿、蓝、黄、青、紫、白 键 8-14 按下,依次熄灭红、绿、蓝、黄、青、紫、白 键 15 按下,蜂鸣器响 ; 键 16 按下,蜂鸣器不响 如有好的优化建议,还请不吝赐教 直接上代码 keypad.h #include sys.h #ifndef _KeyPad_H #define _KeyPad_H void KeyInit(void); //判断是否有键按下u8 u8 KeyDown(void); //矩阵按键扫描,返回一个键值 u8 KeyCheck(void); //功能实现 void KeySwitch(v
[单片机]
S3C2440和S3C6410性能比较
比较项目 S3C2440 S3C6410 内核 ARM920T ARM1176JZF-S 主频 400MHZ 533MHZ/667MHZ 处理器类型 16/32-bit RISC 16/32-bit RISC 设计目标 高性能、低功耗 高性能、低功耗、高性价比 主要应用
[单片机]
S3C2440和<font color='red'>S3C6410</font>性能比较
搭建测试环境——针对S3C6410开发板
(一)前言 目前市面上的开发板型号和种类很多,但目前最流行的是基于三星S3C6410 ARM11架构的开发板。国内很多厂商在S3C6410 ARM11架构的开发板的基础上进行了扩展,开发了扩展板,本博文针对OK6410-A开发板 S3C6410是由三星公司推出的一款低功耗、高性价比的RISC处理器,它基于ARM11内核(ARM1176JZF-S),可广泛应用于移动电话和通用处理等领域。 (二)安装串口调试工具:minicom OK6410开发板带了一个串口,可以通过串口线与PC连接,Linux驱动在输出调试信息的同时会通过串口线将调试信息发送到PC上,这样Linux驱动程序员就可以直接在PC上查看调试信息了。 minicom是一款
[单片机]
搭建测试环境——针对<font color='red'>S3C6410</font>开发板
s3c6410_uart初始化及读写
参考: 1)《USER'S MANUAL-S3C6410X》第31章 UART 2)u-boot uart初始化及读写:u-boot-x.x.x/board/samsumg/smdk6410/lowlevel_init.S              u-boot-x.x.x/cpu/s3c64xx/serial.c 3) 内核串口驱动:linux-x.x.x/driver/tty/serial/s3c6400.c samsung.c serial_core.c 代码: uart.c 1 #include uart.h 2 3 #define GPACON (*((volatile unsigned lo
[单片机]
S3C2440、S3C6410、S5PV210中断解析
写完S5PV210的按键中断程序后,我才知道 6410只是一个过渡产品 确实是正确的,为什么这样说呢?下面我就给大家进行详细的阐述: 中断处理过程等等我就不讲了,一期视频里面已经讲得非常详细了,建议大家在学习本章前,把2440和6410的关于中断的视频再看一次。接下来,我就直接对比他们吧: (1).对于2440: 中断向量只出现在start.s开始部分,类容如下: .globl _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc
[单片机]
将马达驱动器连接至PWM源的设计方法
如何将PWM逻辑信号源连接至电池供电的马达驱动器是我们面临的一道难题。本文介绍了将马达驱动器连接至PWM源的设计方法,其中包括相关方程式与组件选择指南。该方法所采用的电路包括具有精确度与敏感性分析的示例。 将马达驱动器连接至PWM源 LM4570是一种偏心旋转质量(ERM)与线性谐振激励(LRA)马达驱动IC,适用于移动电话及其它便携式媒体设备。本文的设计详细说明了将LM4570连接至PWM源的设过程。 虽然LRA马达是由交流双极型波形以接近LRA的谐振频率驱动,但ERM马达主要由直流电压驱动。由于需要采用直流电,因而可能不会出现交流耦合电容器与驱动器IC的输入端串联。 设计与驱动器IC连接的PWM接口需要大量数学知识以确保运算正
[电源管理]
将马达<font color='red'>驱动</font>器连接至<font color='red'>PWM</font>源的设计方法
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved