远程视频监控之驱动篇(PWM)

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38515237

一.代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/uaccess.h>
#include <asm/mach/time.h>
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#define PWM_IOCTL_SET_FREQ		1
#define PWM_IOCTL_STOP			0
static  int major;

static struct class *wvm_pwm_class;  

static struct semaphore lock;

static void PWM_Set_Freq( unsigned long freq )
{
	//定义局部变量
	unsigned long tcnt;
	unsigned long tcon;
	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); //设置GPB0为输出引脚

        //读取寄存器
	tcon = __raw_readl(S3C2410_TCON);
	tcfg1 = __raw_readl(S3C2410_TCFG1);
	tcfg0 = __raw_readl(S3C2410_TCFG0);

	//prescaler = 50
	tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;  //S3C2410_TCFG_PRESCALER0_MASK(0xff)定时器0和1的预分频值的掩码,TCFG[0~8]
	tcfg0 |= (50 - 1);                       //预分频50

	//mux = 1/16
	tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;       //清零S3C2410_TCFG1_MUX0_MASK(0xf)
	tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;       //设置tcfg1的值为0x0011即:1/16

	__raw_writel(tcfg1, S3C2410_TCFG1);      //将值tcfg1写入定时器配置寄存器1中
	__raw_writel(tcfg0, S3C2410_TCFG0);      //将值tcfg0写入定时器配置寄存器1中

	clk_p = clk_get(NULL, "pclk");
	pclk  = clk_get_rate(clk_p);             //从系统平台时钟队列中获取pclk的时钟频率,在include/linux/clk.h中定义
	tcnt  = (pclk/50/16)/freq;               //计算定时器0的输出时钟频率(pclk/{prescaler0 + 1}/divider value)

	__raw_writel(tcnt, S3C2410_TCNTB(0));    //设置定时器0计数缓存寄存器的值
	__raw_writel(tcnt/2, S3C2410_TCMPB(0));  //设置定时器0比较缓存寄存器的值

	tcon &= ~0x1f;
	tcon |= 0xb;		//disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0(关闭死区、自动重载、关反相器、更新TCNTB0&TCMPB0、启动定时器0)
	__raw_writel(tcon, S3C2410_TCON);//设置定时器控制寄存器的0-4位,即对定时器0进行控制

	tcon &= ~2;			//clear manual update bit(清除定时器0的手动更新位)
	__raw_writel(tcon, S3C2410_TCON);
}

static void wvm_pwm_drv_Stop(void)
{
	s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT); //设置GPB0为输出引脚
	s3c2410_gpio_setpin(S3C2410_GPB(0), 0);                   //设置为0,使蜂鸣器停止
}

static int wvm_pwm_drv_open(struct inode *inode, struct file *file)
{
	if (!down_trylock(&lock))  //如果第一次打开能获取到返回一个0,如果在没有释放前,再次要打开会返回一个非0值
		return 0;
	else
		return -EBUSY;

}

/*cmd 是1,表示设置频率;cmd 是0 ,表示停止pwm*/
static long wvm_pwm_drv_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{
	switch (cmd)
	{
	case PWM_IOCTL_SET_FREQ:
		if (arg == 0)               //若果参数是0,则返回错误
			return -EINVAL;
		PWM_Set_Freq(arg);
		break;

	case PWM_IOCTL_STOP:
		wvm_pwm_drv_Stop();
		break;
	}

	return 0;
}

static int wvm_pwm_drv_close(struct inode *inode, struct file *file)
{
        wvm_pwm_drv_Stop();    //蜂鸣器停止
        up(&lock);             //释放互斥锁
	return 0;
}

static struct file_operations wvm_pwm_drv_fops = {
           .owner            =  THIS_MODULE,      /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
           .open             =  wvm_pwm_drv_open,
	   .unlocked_ioctl   =  wvm_pwm_drv_ioctl,
	   .release          =  wvm_pwm_drv_close,

};

static int wvm_pwm_drv_init(void)
{
	major = register_chrdev(0, "wvm_pwm_drv", &wvm_pwm_drv_fops);

	if(major < 0)
        {
          printk(  " wvm_pwm_drvregister falid!/n");
          return major;
        }

	wvm_pwm_class = class_create(THIS_MODULE, "wvm_pwm_drv");

	if(IS_ERR(wvm_pwm_class))
        {
          printk( " wvm_pwm_drv register class falid!/n");
          return -1;
        }

	/* 为了让mdev根据这些信息来创建设备节点 */
	device_create(wvm_pwm_class, NULL, MKDEV(major, 0), NULL, "wvm_pwm"); /* /dev/wvm_pwm */
	sema_init(&lock, 1);     //定义互斥锁 

	return 0;
}

static void wvm_pwm_drv_exit(void)
{
	unregister_chrdev(major, "wvm_pwm_drv");
	device_destroy(wvm_pwm_class, MKDEV(major, 0));
	class_destroy(wvm_pwm_class);
}

module_init(wvm_pwm_drv_init);

module_exit(wvm_pwm_drv_exit);

MODULE_LICENSE("GPL");

二.应用测试

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <math.h>

int main(int argc, char **argv)
{
    int tmp;
    int cmd;
    int fd;

    //打开蜂鸣器设备
    fd = open("/dev/wvm_pwm", O_RDWR);

    if(fd < 0)
    {
        printf("Open PWM Device Faild!\n");
        exit(1);
    }

    while(1)
    {
    	cmd=1;
 	ioctl(fd,cmd,700); //蜂鸣器响
        usleep(800000);    //延时
        ioctl(fd,cmd,2000);
        usleep(800000);

    }
    //关闭设备
    close(fd);

    return 0;
}

三.分析

1.调用过程

应用程序:ioctl(fd,cmd,700);   调用---> 驱动程序:wvm_pwm_drv_ioctl()

cmd=1  ,arg不等于0       调用--->  
PWM_Set_Freq()

由此我们看到PWM_Set_Freq()才是整个驱动的核心,下面我将结合硬件来讲解这个函数

2.如何实现

a.设置GPB0为PWM引脚

b.设置定时器配置寄存器(TCFG0,TCFG1),目的是设定定时器的输出频率(这两个寄存器的值决定了输出频率)

预分频值:本程序设为了50

分频值设为1/16

c.设置定时器0计数缓存器(TCNTB0控制PWM频率)和定时器0比较缓存器(TCMTB0控制PWM值),其中TCMTB0为TCNTB0的一半,即占空比为百分之50,输出频率:tcnt  = (pclk/50/16)/freq;  其中freq即为我们设定的频率参数。(这里的调节蜂鸣器,只是固定的占空比调节输出频率,如果想调光等,需要的是固定频率,调节占空比,大家可以改动驱动自己尝试下)虽然在本项目中没遇到,但是我觉得还是有必要讲解下,占空比是如何调节的

首先要明确一点当设定完TCNTB0,TCMTB0他们就不变了,TCNTB0对应的内部寄存器TCNT0开始递减
。当其等于TCMTB0电平翻转,当其变为0时,电平再次翻转。所以想控制占空比的话,只需要控制TCNTB0即可。

d.设置定时器控制寄存器(TCON)

首先:关闭死区、自动重载、关反相器、更新TCNTB0&TCMPB0(第一次必须手动更新)、启动定时器0

然后:清楚手动更新,因为已经设置了自动重载。

参考:http://blog.chinaunix.net/uid-25445243-id-212935.html

远程视频监控之驱动篇(PWM),布布扣,bubuko.com

时间: 2024-10-13 01:14:03

远程视频监控之驱动篇(PWM)的相关文章

远程视频监控之驱动篇(摄像头)

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38515279 一.linux摄像头驱动框架 二.UVC介绍 UVC是USB video class的简称,图像产品在不需要安装任何的驱动程序下即插即用.我们通常所说的免驱摄像头. 免驱并不是说没有,而是大家硬件上都支持UVC这个规范,所以linux中有了一个通用的驱动.所以你再插上你的摄像头就不用下载驱动了,自动加载. 三.驱动分析 1.驱动的注册: 驱动在\drivers\

远程视频监控之驱动篇(串口)

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38638831 由于串口驱动略显复杂,且调试比较困难,我并没有进行重新改写,这里主要是分析一下三星的串口驱动.GSM是通过串口通信的,GSM模块的内容我将在应用篇中讲解.在阅读下面内容时我强烈建议你打开内核的驱动代码,而且为了方便建议你使用Source Insight进行阅读代码.驱动位置:\linux-3.4.91\drivers\tty\serial\samsung.c 由

远程视频监控之驱动篇(按键)

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38515211 这里我只贴出了代码和应用,没有进行其他的讲解.因为之前我写过的按键驱动的恩恩怨怨,讲解的非常清楚,这个驱动就是根据之前写的改写而成.连接:http://blog.csdn.net/ruoyunliufeng/article/details/23946487 一.代码 #include <linux/module.h> #include <linux/sc

远程视频监控之硬件篇

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38513927 主要对本项目所设计的硬件进行说明,为了以后的驱动打基础.总的框图在概述里面有说,这里就不再累述. 一.ARM9开发板(mini2440) 1.LED 2.按键 应用程序用的是按键4 3.PWM 4.串口 由于CON1是调试的串口,CON3是红外的串口.所以我们就用CON2. 二.GSM模块(sim900A) 对于SIM900A的介绍不就不说了,百度一下一坨.主要

远程视频监控之应用篇(环境搭建)

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38515423 这篇主要是讲远程视频监控的环境搭建,中间会设计到网络搭建,也会涉及到一些应用和库的移植. 一.配置内核 1.支持UVC(USB摄像头) make menuconfig <*> Multimedia support  ---> <*>   Video For Linux [*]   Video capture adapters (NEW)  -

远程视频监控之应用篇(mjpg-streamer)

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38515311 这篇文章将主要结合源码介绍mjpg-streamer,使小伙伴们了解视频监控的实现. 一.移植 tar xvf mjpg-streamer-r63.tar.gz cd mjpg-streamer-r63 修改所有的Makefile --(1) 将 CC=gcc 修改为 CC=arm-linux-gcc --(2) 修改plugins/input_uvc/Makf

远程视频监控之构思篇

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38462753 一.项目产生 这个项目的产生事实上是个意外,由于我原本假期是像做一个类似于手机的项目.可是后来苦于自己能力有限,无法在短期内作出UI.我在无意中产生了这个项目,实话实说这个mjpg-streamer在web视频监控上已经被别人用烂了,特别是一个老外移植以后,还被友善之臂收到官方文档,当做一个项目.大家几年前看着新颖都尝试这做,我最初一看确实没什么兴趣.网上一搜全

远程视频监控项目之概览

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38457827 这个项目是假期花费足足办个月才搞定的. 从今天开始我将从0开始介绍我的整个项目,其中包括从开始的构思.实施.再到执行.希望大家能从中有所收获,关于代码和文档,我还在整理,应该在写完这个项目之前能够全部整理完,到时候一并放出. 效果视频:http://v.youku.com/v_show/id_XNzUzMzA1MTg0.html 一.功能介绍 1.视频监控功能

转:FFmpeg的远程视频监控系统编解码

0 引言 随着视频编解码技术.计算机网络技术.数字信号处理技术和嵌入式系统的发展,以嵌入式网络视频服务器为核心的远程视频监控系统开始在市场上崭露头角.该系统把摄像机输出的模拟视频信号通过内置的嵌入式视频编码器直接转换成视频流,通过计算机网络传输出去.嵌入式网络视频服务器具备视频编码处理.网络通信.系统控制等强大功能,直接支持网络视频传输和网络管理,使得监控范围达到前所未有的广度.在远程视频监控系统中,摄像头获取的原始视频流在传输之前需要压缩,而FFmpeg可以将原始视频压缩为H264格式视频流,