rk3288模拟可调占空比pwm波形

一、内核为高精度定时器重新设计了一套软件架构,它可以为我们提供纳秒级的定时精度,以满足对精确时间有迫切需求的应用程序或内核驱动,以下学习使用hrtimer(high resolution timer)高精度定时器。
二、hrtimer_init函数初始化定时器工作模式。which_clock可以是CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_BOOTTIME中的一种,mode则可以是相对时间HRTIMER_MODE_REL,也可以是绝对时间HRTIMER_MODE_ABS。
void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,
enum hrtimer_mode mode);

三、设定超时回调函数。
timer.function = hr_callback;

四、使用hrtimer_start激活该定时器。根据time和mode参数的值计算hrtimer的超时时间,并设置到timer->expire域。 expire设置的是绝对时间,所以如果参数mode的值为HRTIMER_MODE_REL(即参数tim的值为相对时间),那么需要将tim的值修正为绝对时间:expire = tim + timer->base->get_time(),调用enqueue_hrtimer,将hrtimer加入到红黑树中。
int hrtimer_start(struct hrtimer *timer, ktime_t tim,
const enum hrtimer_mode mode);

五、使用hrtimer_cancel取消一个hrtimer。
int hrtimer_cancel(struct hrtimer *timer);

六、定时器一旦到期,function字段指定的回调函数会被调用,该函数的返回值为一个枚举值,它决定了该hrtimer是否需要被重新激活。
enum hrtimer_restart {
HRTIMER_NORESTART, /* Timer is not restarted /
HRTIMER_RESTART, /
Timer must be restarted */
};

七、把hrtimer的到期时间推进一个tick周期,返回HRTIMER_RESTART表明该hrtimer需要再次启动,以便产生下一个tick事件。
hrtimer_forward(timer, now, tick_period);
return HRTIMER_RESTART;

示例为模拟pwm波

形控制占空比调节风扇的速度

/*
 * linux/drivers/video/backlight/dc_fan.c
 * direct current fan driver
 */
	
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define GPIO_HIGH	1
#define	GPIO_LOW	0

int FAN_OUT_GPIO;
int FAN_EN_GPIO;

int fan_freq=1000;	//1000-1Khz
int duty_cycle=40;
int temp;
static struct hrtimer dc_timer;
ktime_t kt;

ssize_t dcfan_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	int ret;
	char *data;
	char *first,*second;
	
	printk(KERN_EMERG "%s,line:%d\n",__FUNCTION__,__LINE__);
	
	if(!copy_from_user((char *)data, buf, count))
	{
		printk(KERN_EMERG "%s,1,data:%s,count=%d\n",__FUNCTION__,data,count);
		first	= strsep(&data,",");
		second	= data;

		ret = kstrtoint(first,10,&temp);
		if(ret){
			printk(KERN_EMERG "%s,line:%d,kstrtoint-err\n",__FUNCTION__,__LINE__);
			return -1;
		}
		if(temp<100)	duty_cycle = temp;	//0
		
		ret = kstrtoint(second,10,&temp);
		if(ret){
			printk(KERN_EMERG "%s,line:%d,kstrtoint-err\n",__FUNCTION__,__LINE__);
			return -1;
		}
		if(temp<10000)	fan_freq = 1000000/temp;	//fan_freq<10000Hz
		
		printk(KERN_EMERG "App write duty_cycle=%d,fan_freq=%d\n",duty_cycle,fan_freq);
		return count;
	}
	else{
		return -1;
	}
}

ssize_t dcfan_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	size_t cnt;
	char data[10]={0};
	
	printk(KERN_EMERG "%s-line:%d: enter\n",__FUNCTION__,__LINE__);

	sprintf(data,"%d,%d",duty_cycle,1000000/fan_freq);
	printk(KERN_EMERG "%s,duty_cycle=%d,fan_freq=%dHz,data=%s\n",\
		__FUNCTION__,duty_cycle,fan_freq,data);

	cnt = strlen(data);
	if(!copy_to_user((char *)buf, data, cnt))
		return 0;
	else
		return -1;
}

static int dcfan_open(struct inode *inode, struct file *file)
{
	printk(KERN_EMERG "%s-line:%d: enter\n",__FUNCTION__,__LINE__);
	return 0;
}

static struct file_operations dcfan_ops = {
	.owner = THIS_MODULE,
	.open = dcfan_open,
	.read = dcfan_read,
	.write = dcfan_write,
};

enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)
{
	unsigned long valid_value=0;
	static int value=0;
	//printk(KERN_EMERG "%s-line:%d\n",__FUNCTION__,__LINE__);
	
	value++;
	if(value%2){
		valid_value = 1000*duty_cycle*fan_freq/100;
		gpio_set_value(FAN_OUT_GPIO,GPIO_HIGH);
	}
	else{
		valid_value =1000*(100-duty_cycle) * fan_freq/100;
		gpio_set_value(FAN_OUT_GPIO,GPIO_LOW);
	}

	kt = ktime_set(0,valid_value);
	hrtimer_forward(timer,timer->base->get_time(),kt);
	
	return HRTIMER_RESTART;
}

static int get_dts_gpio(struct platform_device *pdev)
{
	int ret ;
	enum of_gpio_flags flag;
	struct device_node *fan_node = pdev->dev.of_node;
	
	/********FAN_OUT_GPIO********/
	FAN_OUT_GPIO = of_get_named_gpio_flags(fan_node,"dcfan-out-gpios",0,&flag);
	if (!gpio_is_valid(FAN_OUT_GPIO)){
		printk(KERN_INFO "hello: invalid gpio : %d\n",FAN_OUT_GPIO);
		return -1;
	}
	ret = gpio_request(FAN_OUT_GPIO, "fan_out_gpio");
	if (ret) {
		gpio_free(FAN_OUT_GPIO);
		return -EIO;
	}
	gpio_direction_output(FAN_OUT_GPIO, GPIO_HIGH);

	/********FAN_EN_GPIO********/
	FAN_EN_GPIO = of_get_named_gpio_flags(fan_node,"enable-gpios",0,&flag);
	if (!gpio_is_valid(FAN_EN_GPIO)){
		printk(KERN_INFO "hello: invalid gpio : %d\n",FAN_EN_GPIO);
		return -1;
	}
	ret = gpio_request(FAN_EN_GPIO, "fan_en_gpio");
	if (ret) {
		gpio_free(FAN_EN_GPIO);
		return -EIO;
	}
	gpio_direction_output(FAN_EN_GPIO, GPIO_HIGH);

	return 0;
}

struct miscdevice dc_fan_dev = {
	.minor	=	MISC_DYNAMIC_MINOR,
	.name	=	"dc-fan",
	.fops	=	&dcfan_ops,
};


static int dc_fan_probe(struct platform_device *pdev)
{	
	int ret;
	dev_info(&pdev->dev, "%s,line:%d: enter\n",__FUNCTION__,__LINE__);

	get_dts_gpio(pdev);

	ret = misc_register(&dc_fan_dev);
	
	kt = ktime_set(0,500);
	hrtimer_init(&dc_timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
	hrtimer_start(&dc_timer,kt,HRTIMER_MODE_REL);
	dc_timer.function = hrtimer_hander;
	
	printk(KERN_INFO "%s-line:%d: exit\n",__FUNCTION__,__LINE__);
	
	return 0;
}

static int dc_fan_remove(struct platform_device *pdev)
{
	printk(KERN_INFO "Enter %s\n", __FUNCTION__);
	gpio_free(FAN_OUT_GPIO);
	gpio_free(FAN_EN_GPIO);
	misc_deregister(&dc_fan_dev);
	hrtimer_cancel(&dc_timer);
	return 0;
}

static void dc_fan_shutdown(struct platform_device *pdev)
{
	dc_fan_remove(pdev);
}

static const struct of_device_id of_dc_fan_match[] = {
	{ .compatible = "dc-fan", },
	{},
};

static struct platform_driver dc_fan_driver = {
	.probe		= dc_fan_probe,
	.remove		= dc_fan_remove,
	.shutdown	= dc_fan_shutdown,
	.driver	= {
		.name	= "dc-fan",
		//.pm	= GPIO_FAN_PM,
#ifdef CONFIG_OF_GPIO
		.of_match_table = of_match_ptr(of_dc_fan_match),
#endif
	},
};


module_platform_driver(dc_fan_driver);

MODULE_DESCRIPTION("DC FAN Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gpio-fan");


你可能感兴趣的:(C语言,linux学习,Android)