背景:最近项目基于海思HI3536芯片做了一款设备,原本设计了CPLD逻辑控制可以风扇调速,后面由于降成本的原因砍掉了CPLD逻辑,同时竞品的风扇也没有调速功能,默认全速转,为了差异化,项目组决定用GPIO模拟PWM波做个简单的调速功能,当然精度要求不是很严格。
硬件电路:
实现原理:
为了精度考虑,将功能放在了内核态实现,同时采用内核定时器,根据目标速度来动态调整GPIO的高低时间达到模拟调整占空比进而实现PWM波形的功能,目前内核频率设置成了100HZ,功能验证OK,信号质量等由于项目还处于前期预研阶段,硬测没有投入,后续待项目正式启动后再根据信号质量的测试结果决定是否调整频率。(然后后续再补充用户态接口,结合风扇调速算法实现完整的自动调速功能--这部分工作这里就不体现了)
实现代码:
-
#define FAN_VERSION "0.1"
-
static char version[] __initdata = KERN_INFO "" "FAN Module Driver" " :" __DATE__", "__TIME__ "\n";
-
-
static struct timer_list fan_adjust_timer;
-
unsigned int g_fan_pwm = 20;/*风扇PWM值*/
-
module_param(g_fan_pwm, uint, S_IRUGO);
-
-
/*GPIO基地址*/
-
#define GPIO_NUM_BASE(num) (0x12150000 + 0x10000*(num))
-
/*管脚复用寄存器基地址*/
-
#define MUXCTRL_REG_BASE (0x120f0000)
-
-
#define FAN_HW_REG(reg) *((volatile unsigned int *)(reg))
-
-
-
static void fan_adjust(unsigned int fan_pwm)
-
{
-
/*GPIO与PWM波相反*/
-
static int i = 0;
-
-
if (i % 2 == 0)
-
{
-
FAN_HW_REG(IO_ADDRESS(GPIO_NUM_BASE(4) + 0x80)) = 0x20;/*GPIO4_5拉高*/
-
fan_adjust_timer.expires = jiffies + ((100 - fan_pwm) * HZ / 1000);
-
}
-
else
-
{
-
FAN_HW_REG(IO_ADDRESS(GPIO_NUM_BASE(4) + 0x80)) = 0x0;/*GPIO4_5拉低*/
-
fan_adjust_timer.expires = jiffies + (fan_pwm * HZ / 1000);
-
}
-
-
i++;
-
fan_adjust_timer.data = g_fan_pwm;
-
-
add_timer(&fan_adjust_timer);
-
}
-
-
static int __init fan_init(void)
-
{
-
printk(version);
-
-
FAN_HW_REG(IO_ADDRESS(MUXCTRL_REG_BASE + 0xc0)) = 0x3; /*配置GPIO4_5管脚复用为通用GPIO,11b',PWM*/
-
FAN_HW_REG(IO_ADDRESS(MUXCTRL_REG_BASE + 0xc8)) = 0x3; /*配置GPIO4_7管脚复用为通用GPIO,11b',FG*/
-
-
FAN_HW_REG(IO_ADDRESS(GPIO_NUM_BASE(4) + 0x400)) = 0xA0; /*配置GPIO4_5/GPIO4_7为输出*/
-
FAN_HW_REG(IO_ADDRESS(GPIO_NUM_BASE(4) + 0x280)) = 0x0; /* PADDR[9:2]分别对应 GPIO_DATA[7:0],默认设置为高*/
-
-
init_timer(&fan_adjust_timer);
-
-
fan_adjust_timer.function = fan_adjust;
-
fan_adjust_timer.data = g_fan_pwm;
-
fan_adjust_timer.expires = jiffies + (HZ / 100);
-
-
add_timer(&fan_adjust_timer);
-
-
printk(KERN_INFO"fan: version %s, fan driver init successful!\n", FAN_VERSION);
-
-
return 0;
-
}
-
-
*******************************************************************************/
-
static void __exit fan_exit(void)
-
{
-
del_timer_sync(&fan_adjust_timer);
-
}
-
-
module_init(fan_init);
-
module_exit(fan_exit);
-
-
MODULE_AUTHOR("xxx");
-
MODULE_DESCRIPTION("xxx");
-
MODULE_LICENSE("GPL");
-
MODULE_VERSION(FAN_VERSION);
调试问题:早期调试过程中,高低电平间的保持时间采用了mdelay函数,结果发现时间存在不精确的情况,同时CPU占用率偏高,因为
通过动态调整定时器的expires 来实现,实测精度比较高
阅读(4372) | 评论(0) | 转发(0) |