Firefly开源社区

标题: 《小试》根据cpu温度控制风扇转速 [打印本页]

作者: madman    时间: 2015-5-12 14:15
标题: 《小试》根据cpu温度控制风扇转速
本帖最后由 madman 于 2015-5-12 14:15 编辑

    之前刚拿到的板,搭建好基本的环境之后就想着进一步学习一下,不过限于初学者能力有限,不知道做什么好。后面在论坛乱逛无意间看到一个根据cpu温度控制风扇开关的应用,觉得挺有意思的。不过这个应用只是测到温度使用io口控制开关。然后我就想着使用pwm达到平时我们电脑散热风扇的那种效果,然后以此对驱动进行学习。然后就有下面那么个东西~~
    首先我使用的是官方默认板的Android SDK ,然后对它进行了编译。其后我主要是修改了kernel中原来的驱动,然后给上层留了个接口作为开关,测量温度和控制pwm都在驱动中完成了。额。。还有就是原带的风扇是不带pwm的接口的,这也让我郁闷了下,然后使用了个简单的三极管开关电路把pwm接口加了进去。然后根据之前看到的帖子,我们可以cat板子上的sys/class/hwmon/hwmon0/device/temp0_input,然后它就会打印出温度。根据这个文件夹我找到了它对应的驱动,在sdk里的kernel/drivers/hwmon/rockchip-hwmon.c里。然后我就对rockchip-hwmon.c这个驱动进行了小小的添加。这个驱动里上层的接口函数是show_input,然后我复制了这个函数并把它的return buf部分去掉,然后把他定义成了外部函数,这样就可以在别的驱动里调用它读取温度。至于pwm,我是在原来的背光pwm里修改的。背光驱动在kernel/drivers/video/backlight/pwm_bl.c上。首先这是背光的dts,添加进kernel/ arch/arm/boot/dts/rk3288.dtsi里面就可以了

backlight {
          compatible = "pwm-backlight";
          pwms = <&pwm1 0 10000>;//0 10000
          rockchip,pwm_id= <1>;
          brightness-levels = <214 213 212 211 210 209 208 207 206 205 204 203 202 201 200 199 198 197 196 195 194 193 192 191 190 189 188 187 186 185 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170>;
          default-brightness-level = <180>;//180
          enable-gpios = <&gpio8 GPIO_A6 GPIO_ACTIVE_HIGH>;
      };
至于控制pwm占空比使用的是这个函数pwm_config(&w_pwm, 1000, 10000);至于功能的实现我使用了一个线程在线程里每隔一秒读取一次温度然后调整对应的pwm。原来使用的是定时器,然后发现定时器不能带参数,带了就崩溃~_~..最后使用proc_create创建了个简单的读写接口给上层调用控制开和关。
    好吧,大概就是这样,也不罗嗦了,下面是相关的图和部分代码
rockchip-hwmon.c
extern int show_input_pwm(struct device *dev,
              struct device_attribute *devattr)//显示温度功能的实现
{
    int  temp;
    struct rockchip_temp *data = dev_get_drvdata(dev);//获取数据
    struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    u8 tsadc_addr = data->tsadc_addr[attr->index];

    temp = data->ops.read_sensor(tsadc_addr);

    hwmon_cpu_wendu = temp;
    return 0;
}
extern void show_cpu(void)
{
    show_input_pwm(&(fpdev->dev),&sensor_dev_attr_temp0_input.dev_attr);
}
pwm_bl.c
int func(void* data)  
{  
    int high_pwm;
      while(1)  
    {  
            if( kthread_should_stop())  return -1;  
        show_cpu();
        printk("%d\n",hwmon_cpu_wendu);

        if(hwmon_cpu_wendu > 0 )
        {   
            if(hwmon_cpu_wendu <= 40)
                pwm_config(&w_pwm, 100, 10000);
            else if((hwmon_cpu_wendu>40)||(hwmon_cpu_wendu<80))
            {
                high_pwm = hwmon_cpu_wendu*125;
                pwm_config(&w_pwm, high_pwm, 10000);
            }   
            else if(hwmon_cpu_wendu >= 80)
                pwm_config(&w_pwm, 9800, 10000);
        }
   
        
           printk(KERN_ALERT "func running\n");  

            set_current_state(TASK_UNINTERRUPTIBLE); //设置进程的状态
              schedule_timeout(1*HZ);  //在指定的时间到期后(timeout了)将进程唤醒
        if(out_pthread == 1)//退出
        {
            pwm_config(&w_pwm, 100, 10000);
            break;
        }
      }   
      return 0;  
}
probe里:
       proc_create("pwm",0666,NULL,&proc_fops);
       msg=kmalloc(GFP_KERNEL,FANBUFSIZE*sizeof(char));
       w_pwm = *(pb->pwm);
       mytask=kthread_create(func,0,"mykthread");  
       wake_up_process(mytask);


之后的话进一步会将pwm的驱动从背光里单独拿出来,做成一个单独的驱动
pwm.zip (14.44 KB, 下载次数: 106)


QQ截图20150512140911.png (791.33 KB, 下载次数: 580)

QQ截图20150512140911.png

作者: zhansb    时间: 2015-5-12 14:33
赞一个:)
作者: Firefly    时间: 2015-5-12 15:34
支持原创
作者: madman    时间: 2015-5-13 11:11
经过进一步的修改,已经把程序的功能从背光当中单独抽取了出来,相对应的dts如下,然后把线程读取温度控制pwm改成了工作队列的方式实现

static void work_timer_function(int para)
{
        if(schedule_work(&work_work_q) == 0)//调度执行一个具体的任务
    {
            printk("<0> cannot schedule work !!!\n");
        }
        counter++;
}

static void work_timer_register(struct timer_list* ptimer)
{
        init_timer(&work_timer);
        work_timer.data = 250;
        work_timer.expires = jiffies + 50;
        work_timer.function = work_timer_function;
        add_timer(&work_timer);
}


static void work_fectch_thread(struct work_struct *work)
{
    int high_pwm;
    if((out_thread == 0)||(out_thread == 2))
    {
        if(out_thread == 2)
            pwm_enable(&w_pwm);
            show_cpu();
           printk("wendu: %d\n",hwmon_cpu_wendu);
            if(hwmon_cpu_wendu > 0 )
        {   
            if(hwmon_cpu_wendu <= 40)
                pwm_config(&w_pwm, 10, 10000);
            else if((hwmon_cpu_wendu>40)||(hwmon_cpu_wendu<80))
            {
                high_pwm = hwmon_cpu_wendu*125;
                if(high_pwm <= 10000)
                    pwm_config(&w_pwm, high_pwm, 10000);
            }   
            else if(hwmon_cpu_wendu >= 80)
                pwm_config(&w_pwm, 9999, 10000);
        }
   
    }
    else if(out_thread == 1)
    {
        pwm_config(&w_pwm, 0, 10000);
        pwm_disable(&w_pwm);
        del_timer(&work_timer);   
    }
    work_timer_register(&work_timer);
}


dts
   backlight {
          compatible = "pwm-backlight";
          pwms = <&pwm1 0 10000>;//0 10000
          rockchip,pwm_id= <1>;
      };

probe
    work_timer_register(&work_timer);
        //初始化工作队列并将工作队列与处理函数绑定
        INIT_WORK(&work_work_q,work_fectch_thread);
pwm_bl.c.zip (2.28 KB, 下载次数: 93)



作者: zhang1984    时间: 2015-5-17 22:13
显示show-cpu函数定义不对呀
作者: madman    时间: 2015-5-18 09:00
zhang1984 发表于 2015-5-17 22:13
显示show-cpu函数定义不对呀

额。。怎么不对法?这函数调用的时候去读取一次cpu温度值,使得变量hwmon_cpu_wendu 更新为当前温度。
作者: zhang1984    时间: 2015-5-18 13:00
显示 “rk_headset_irq_hoot_adc.c(.text+142bc):undefined to 'show_cpu'”
作者: madman    时间: 2015-5-18 14:17
zhang1984 发表于 2015-5-18 13:00
显示 “rk_headset_irq_hoot_adc.c(.text+142bc):undefined to 'show_cpu'”

你只是在rockchip-hwmon.c修改,没有在pwm声明的话就会出现这样的错误,我好像之前也试过。
作者: zhang1984    时间: 2015-5-18 14:29
我下在的文件,没有做任何修改,直接替换的, 我的qq361899636加一下好向你请教
作者: madman    时间: 2015-5-18 15:02
zhang1984 发表于 2015-5-18 14:29
我下在的文件,没有做任何修改,直接替换的, 我的qq361899636加一下好向你请教

ok
作者: zxx686131    时间: 2016-7-21 17:30
不错,顶一个!
作者: zxx686131    时间: 2016-7-21 17:31
不错!感谢分享。
作者: 214740484    时间: 2016-8-11 20:07
谢谢楼主分享!
作者: zzj    时间: 2016-8-21 15:59
楼主你好,我发现我的程序跟你的类似,但却不能让pwm1口输出pwm波,这是我的程序,麻烦帮我看一下,很重要,万分感谢

#include<linux/pwm.h>
#include<linux/init.h>
#include<linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>

MODULE_LICENSE("GPL");

static int __init pwm_init(void)
{
        int i;
        struct pwm_device * pwm1;
        pwm_free(pwm_request(1, "diy-pwm"));
        pwm1 = pwm_request(1, "diy-pwm");
        pwm_enable(pwm1);
        mdelay(2000);
        for(i=0;i<5;i++)
        {
                pwm_config(pwm1, 1000, 1000000);
                printk("%d 1\n",i);
                mdelay(1000);
                pwm_config(pwm1, 800000, 1000000);
                printk("%d 2\n",i);
                mdelay(1000);
        }
        return 0;
}

static void __exit pwm_exit(void)
{
        printk("Exit pwm\n");
}

subsys_initcall(pwm_init);
module_exit(pwm_exit);
作者: yly123ycyn    时间: 2016-8-23 11:38

作者: bandit1101    时间: 2017-1-25 14:38
支持原创
作者: Evan_RK    时间: 2017-2-6 09:03
不错 哦
作者: Hanlin    时间: 2017-2-14 09:23
学习学习

作者: david11    时间: 2017-2-15 17:07
不错
作者: matt_chou    时间: 2017-3-6 18:53

学习学习
作者: 网老无    时间: 2017-3-9 11:22
赞一个,兄弟
作者: bzhao    时间: 2017-9-13 10:35
赞!!!!
作者: bzhao    时间: 2017-9-13 10:35
赞!!!!
作者: huansering    时间: 2018-6-12 15:56
参考下,谢谢
作者: JohnLee    时间: 2018-7-16 22:22
学习一下

作者: 爱吃小浣熊的土    时间: 2019-6-14 11:57
厉害
作者: z2flood    时间: 2020-1-10 11:30
多谢分享。
作者: 辛晓宇    时间: 2020-11-18 17:21
下载了




欢迎光临 Firefly开源社区 (https://dev.t-firefly.com/) Powered by Discuz! X3.1