论坛» 嵌入式开发» STM32

mtk pwm&&linux timer

高工
2019-02-26 12:45 1楼

pwm控制还是有很多要注意的地方

附上驱动的代码


/*

* drivers/leds/leds-mt65xx.c

*

* This file is subject to the terms and conditions of the GNU General Public

* License. See the file COPYING in the main directory of this archive for

* more details.

*

* Hydrodent weiqifa modify add

*

*/


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

/****************************************************************************

* 现在我们的时钟源是32k

*

* 频率 理论上 1

* f=32/div/frequency div=1 frequency=pwm_setting.duration

* 比如我们设置 f=1 那么我们frequency的值就应该是30

*

* 占空比

* 0

* 实际测试发现 duty 值越大 测量值就越接近测试值

* 并在adb 下面显示出来

*

* 设备文件目录:/sys/class/hdyrodent

* frequency:设置频率 echo 10 > frequency

* duty:设置占空比 echo 50 > duty

* switch:打开关闭 echo 1 >switch 大于0是打开 小于等于0是关闭

*

*提示:如果不设置值,直接打开默认有波形

***************************************************************************/


static struct class *hdyrodent_pwm_class=NULL;

static int show_frequency=123;//默认分辨率变量

static int show_duty=50;//默认占空比变量

static bool show_switch=false;

static int show_stopbit=63;//这个变量可以用来控制分辨率,默认最大值是63 最小值是0


#define PWM_NO PWM4

//声明定时器

static struct hrtimer timer_ptt;

static struct pwm_easy_config pwm_setting;//pwm设置的结构体


/****************************************************************************

* scnprintf是linux下面一个函数,这个函数把后面 的值格式话转化成字符串

* 并在adb 下面显示出来

***************************************************************************/

static ssize_t hdyrodent_frequency_show(struct device *dev,struct device_attribute *attr, char *buf)

{

printk("%s\n", __FUNCTION__);


return scnprintf(buf, PAGE_SIZE, "%d\n", show_frequency);

}

/****************************************************************************

* echo pwm这个节点的时候就会调用下面这个函数,echo "12" > pwm

* 那么value的值就是12 可以通过这样设置pwm的数值

***************************************************************************/

static ssize_t hdyrodent_frequency_store(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)

{

int value=0;

sscanf(_buf, "%d", &value);

sscanf(_buf, "%d", &show_frequency);//把值传给show_frequency这样 cat的值就是echo 进去的值了

printk("%s: value: %d _count:%d\n", __FUNCTION__, value,_count);

if(value<=0)

{

printk("Error %s input value wrong!!!!\n",__FUNCTION__);

}

else

{

pwm_setting.duration=value;

pwm_set_easy_config(&pwm_setting);

printk("Success %s \n",__FUNCTION__);

}


return _count;

}

/****************************************************************************

* scnprintf是linux下面一个函数,这个函数把后面 的值格式话转化成字符串

* 并在adb 下面显示出来

***************************************************************************/

static ssize_t hdyrodent_brightness_show(struct device *dev,struct device_attribute *attr, char *buf)

{

printk("%s\n", __FUNCTION__);


return scnprintf(buf, PAGE_SIZE, "%d\n", show_duty);

}

/****************************************************************************

* echo pwm这个节点的时候就会调用下面这个函数,echo "12" > pwm

* 那么value的值就是12 可以通过这样设置pwm的数值

***************************************************************************/

static ssize_t hdyrodent_brightness_store(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)

{

int value=0;

sscanf(_buf, "%d", &value);

sscanf(_buf, "%d", &show_duty);//把值传给show_duty这样 cat的值就是echo 进去的值了

printk("%s: value: %d _count:%d\n", __FUNCTION__, value,_count);

if(value<=0)

{

mt_pwm_disable(PWM_NO, true);//关闭pwm波

printk("Error: %s disable the pwm 2\n",__FUNCTION__);

}

else

{

pwm_setting.duty = value;

pwm_set_easy_config(&pwm_setting);

printk("Success: %s disable the pwm 2\n",__FUNCTION__);

}

return _count;

}

/****************************************************************************

* scnprintf是linux下面一个函数,这个函数把后面 的值格式话转化成字符串

* 并在adb 下面显示出来

***************************************************************************/

static ssize_t hdyrodent_on_show(struct device *dev,struct device_attribute *attr, char *buf)

{

printk("%s\n", __FUNCTION__);


return scnprintf(buf, PAGE_SIZE, "%d\n", show_switch);

}

/****************************************************************************

* echo pwm这个节点的时候就会调用下面这个函数,echo "12" > pwm

* 那么value的值就是12 可以通过这样设置pwm的数值

***************************************************************************/

static ssize_t hdyrodent_on_store(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)

{

int value=0;

sscanf(_buf, "%d", &value);

sscanf(_buf, "%d", &show_switch);//把值传给show_switch这样 cat的值就是echo 进去的值了

printk("%s: value: %d _count:%d\n", __FUNCTION__, value,_count);

if(value>0)

{

pwm_set_easy_config(&pwm_setting);

printk("Success: %s enable the pwm 2\n",__FUNCTION__);

}

else

{

mt_pwm_disable(PWM_NO, true);//关闭pwm波

printk("Success: %s disable the pwm 2\n",__FUNCTION__);

}

return _count;

}

/****************************************************************************

* __ATTR的第一个参数是在sys文件系统里面显示的名字

 * 0666是这个节点的属性,0666表示是可读可写

 * hdyrodent_frequency_show 是cat 这个文件的时候调用的函数

 * hdyrodent_frequency_store 是echo的时候调用的函数

***************************************************************************/

static struct class_attribute hdyrodent_attr[] = {

__ATTR(frequency,0666, hdyrodent_frequency_show, hdyrodent_frequency_store),

__ATTR(brightness,0666, hdyrodent_brightness_show, hdyrodent_brightness_store),

__ATTR(on,0666, hdyrodent_on_show, hdyrodent_on_store),

__ATTR_NULL,


};

/****************************************************************************

* 定时中断函数

***************************************************************************/

static enum hrtimer_restart timer_ptt_interrupt(struct hrtimer *timer)

{

static unsigned int c=0;

c++;

printk("%s,%d,c=%d\n",__func__,__LINE__,c);

hrtimer_start(&timer_ptt, ktime_set(1, 0), HRTIMER_MODE_REL);

return HRTIMER_NORESTART;

}


static int __init hdyrodent_pwm_init(void)

{

int ret;

int i = 0;


printk("%s start\n", __FUNCTION__);

//用class_create在sys/class/下面生成sys文件系统

hdyrodent_pwm_class=class_create(THIS_MODULE,"hdyrodent_charger_led");

if(IS_ERR(hdyrodent_pwm_class))

{

printk("create hdyrodent module fail \n");

return PTR_ERR(hdyrodent_pwm_class);;

}


for (i = 0 ; NULL != attr_name(hdyrodent_attr[i]);i++)

{

ret = class_create_file(hdyrodent_pwm_class, &hdyrodent_attr[i]);

if (0 != ret)

{

printk("creat %s class file fail\n",attr_name(hdyrodent_attr[i]));

break;

}

}

mt_pwm_disable(PWM_NO, true);//把pwm 功能关闭掉

mt_set_gpio_mode(90,GPIO_MODE_06);

pwm_setting.pwm_no = PWM_NO;//通过函数把这个gpio口设置成pwm1模式,对应pwm_no就是PWM2

pwm_setting.pmic_pad = false;

pwm_setting.duty=20;

pwm_setting.duration=100;

pwm_setting.clk_div = CLK_DIV1;

pwm_setting.clk_src = PWM_CLK_OLD_MODE_32K;//PWM_CLK_OLD_MODE_BLOCK;//26M

//pwm_set_easy_config(&pwm_setting);


//定时器

hrtimer_init(&timer_ptt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

timer_ptt.function = timer_ptt_interrupt;

hrtimer_start(&timer_ptt, ktime_set(1, 0), HRTIMER_MODE_REL);

printk("%s end\n", __FUNCTION__);



return 0;


}


static void __exit hdyrodent_pwm_exit(void)

{

int i = 0;


printk("hdyrodent module cleanup start.\n");

mt_pwm_disable(PWM_NO, true);//把pwm 功能关闭掉

if(hrtimer_cancel(&timer_ptt))

{

printk("try to cancel hrtimer \n");

}

for (i = 0 ; NULL != attr_name(hdyrodent_attr[i]);i++)

{

class_remove_file(hdyrodent_pwm_class, &hdyrodent_attr[i]);

}

class_destroy(hdyrodent_pwm_class);

printk("hdyrodent module cleanup OK!\n");

}


MODULE_AUTHOR("329410527@qq.com");

MODULE_DESCRIPTION("HDYRODENT PWM MODULE");

MODULE_LICENSE("GPL");

MODULE_VERSION("ver0.1");


module_init(hdyrodent_pwm_init);

module_exit(hdyrodent_pwm_exit);



高工
2019-02-27 09:42 2楼

谢谢楼主分享

院士
2019-02-27 10:08 3楼

使用Linux的PWM发生器靠谱不?

话说Linux也不是实时系统,其如何调节占空比啊

共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]