分类: LINUX
2012-07-20 14:21:32
一、 主要函数说明:
1、__raw_readl(a):读物理寄存器
#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
2、__raw_writel(v,a):写物理寄存器
#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
3.init_MUTEX(sem)初始化互斥锁
#define init_MUTEX(sem) sema_init(sem, 1)
#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
void down(struct semaphore *sem);互斥锁锁住
int __must_check down_trylock(struct semaphore *sem);尝试互斥锁锁住
void up(struct semaphore *sem);释放互斥锁
4.了解clk_get及clk_get_rate函数
一个函数的功能是得到的是填充clk结构体数据,另一个函数的功能是得到PCLK。
二、底层驱动程序
/*********************************
** 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
#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
#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
#include
#define DEVICE_NAME "pwm_micro2440_drv"
#define PWM_START 0x01
#define PWM_STOP 0x02
static struct semaphore lock;
static pwm_micro2440_start(unsigned long canshu)
{
unsigned long tcon;
unsigned long tcnt;
unsigned long tcfg1;
unsigned long tcfg0;
struct clk *clk_p;
unsigned long pclk;
//set GPB0 as tout0, pwm output
s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
//读寄存器数值
tcon = __raw_readl(S3C2410_TCON);
tcfg1 = __raw_readl(S3C2410_TCFG1);
tcfg0 = __raw_readl(S3C2410_TCFG0);
//prescaler = 50
tcfg0 =tcfg0&0xffffff00;//将寄存器低8位清0
tcfg0 |= (50 - 1);//设置定时器0的预分频数值
//mux = 1/16
tcfg1 =tcfg1&0xfffffff0;
tcfg1 |= 0x03;
__raw_writel(tcfg1, S3C2410_TCFG1);//写寄存器
__raw_writel(tcfg0, S3C2410_TCFG0);
clk_p = clk_get(NULL, "pclk");//获取PCLK
pclk = clk_get_rate(clk_p);
tcnt = (pclk/50/16)/10;
__raw_writel(tcnt, S3C2410_TCNTB(0));
__raw_writel(tcnt/canshu, S3C2410_TCMPB(0));//调整占空比,当canshu=2的时候占空比为50%
tcon &= ~0x1f;//寄存器低5位清0
tcon |= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
__raw_writel(tcon, S3C2410_TCON);
tcon &= ~2; //clear manual update bit
__raw_writel(tcon, S3C2410_TCON);
}
static pwm_micro2440_stop(void)
{
unsigned long tcon;
tcon=__raw_readl(S3C2410_TCON);
tcon=tcon&(~0x01);
__raw_writel(tcon, S3C2410_TCON);
s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(S3C2410_GPB(0), 0);
}
static int pwm_open(struct inode *inode,struct file *file)
{
int ret;
ret=down_trylock(&lock);
if(ret==0)
return 0;
else
return -EBUSY;
}
static int pwm_close(struct inode *inodep,struct file *file)
{
pwm_micro2440_stop();
up(&lock);//释放互斥锁
return 0;
}
static int pwm_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case PWM_START:
if((arg==0)||(arg==NULL))
return -EINVAL;
else
pwm_micro2440_start(arg);
break;
case PWM_STOP:
pwm_micro2440_stop();
break;
default:
break;
}
return 0;
}
static struct file_operations dev_fops={
.owner=THIS_MODULE,
.open=pwm_open,
.release=pwm_close,
.ioctl=pwm_ioctl,
//.read=lc04_read,
//.write=lc04_write,
};
static struct miscdevice misc={
.name=DEVICE_NAME,
.minor=MISC_DYNAMIC_MINOR,
.fops=&dev_fops,
};
static int __init pwm_micro2440_init(void)
{
int ret;
init_MUTEX(&lock);
ret=misc_register(&misc);
return ret;
}
void __exit pwm_micro2440_exit(void)
{
misc_deregister(&misc);
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("xubin");
module_init(pwm_micro2440_init);
module_exit(pwm_micro2440_exit);
建的是混杂设备所以不用手动创建设备文件,驱动程序中设定了一个变量作为改变PWM占空比,实验的时候我只听了蜂鸣器的响声觉得是通过改变了占空比而达到改变蜂鸣器的响声,至于是否真改了占空比我没有使用示波器观察,如果有错朋友们可以给我提出呵呵。
三、应用程序:
#include
#include
#include
#include
#include
#include
#define PWM_START 0x01
#define PWM_STOP 0x02
int main(int argc,char **argv)
{
unsigned long i=1;
int fd;
fd=open("/dev/pwm_micro2440_drv",O_RDWR);
if(fd<0)
{
printf("error\n");
exit(1);
}
while(1)
{
if(i==0)
{
i=1;
}
ioctl(fd,PWM_START,i);
i+=10;
usleep(300000);
ioctl(fd,PWM_STOP,NULL);
}
close(fd);
return 0;
}