Linux驱动之利用STM32、设备树、pwm子系统实现风扇的分级调控
系 统:Linux 5.10.61
开发板:STM32mp157a
硬 件:风扇
一、首先我们需要对PWM和定时器(TIM)的联系简单的做一下了解,具体详细的PWM原理可见PWM原理 PWM频率与占空比详解。
PWM(脉宽调制)和TIM(定时器)在嵌入式系统中有着紧密的联系。以下是它们之间的主要关系和作用:
(一)、PWM(Pulse Width Modulation)脉宽调制
PWM 是一种用于控制模拟电路的数字信号技术。通过调节脉冲的宽度(即高电平持续时间),可以控制平均输出电压,从而实现对设备如电机、LED亮度的调节。PWM 信号的频率和占空比是两个关键参数。
(二)、TIM(Timer)定时器
TIM 是微控制器中用于计时和产生精确时间间隔的硬件模块。它们通常用于以下几个方面:
- 产生定时中断
- 计数事件(如外部脉冲)
- 产生PWM信号
(三)、PWM 和 TIM 的联系
- PWM的实现依赖于定时器:
- 定时器可以用于产生周期性的中断,进而改变PWM信号的高电平和低电平持续时间。
- 在STM32等微控制器中,定时器模块通常具有专门的PWM模式,可以直接生成PWM信号。通过设置定时器的相关寄存器(如自动重装载寄存器ARR和比较寄存器CCR),可以调节PWM信号的频率和占空比。
- 定时器配置:
- 频率设置:定时器的频率决定了PWM信号的频率。通过设置定时器的预分频器(Prescaler)和自动重装载寄存器(ARR),可以配置定时器的计数频率。
- 占空比设置:PWM信号的占空比由定时器的比较寄存器(CCR)决定。通过改变CCR的值,可以调节PWM信号的高电平时间。
二、编写设备树
1、查看设备原理图,查看风扇的连接方式
硬件连接:
拓展版:
开发板:
上图我们可以看到,我们的风扇模块连接是这样的:风扇—TIM1—PE9—PWM(AF1)功能 到了PE9这个引脚上
内存地址映射:0x44000000
引脚复用:
上图可以看到想要用到pwm(这里是tim1控制)需要将PE9复用为AF1。
下面我们看着原理图以及芯片手册简单的画一下我们的连接图:
2、查看厂商设备树,分析填写内容
先看厂商提供的帮助文档,这是为了让我们知道,我们想建立一个pwm节点都需要得到哪些信息:
帮助文档路径:xxx@xxx:xxxx/linux-5.10.61/Documentation/devicetree/bindings/pwm
读帮助文档得知,我们的pwm节点应该像这样:
pwm1: pwm@fe510000 {
// 定义名为pwm1的PWM控制器节点,地址为0xfe510000
compatible = "st,pwm"; // 指定该设备与"st,pwm"驱动程序兼容
reg = <0xfe510000 0x68>; // 定义寄存器基地址0xfe510000和大小0x68
#pwm-cells = <2>; // 指定pwm-cells的数量为2,即每个PWM描述符包含两个参数
pinctrl-names = "default"; // 定义引脚控制状态名为"default"
pinctrl-0 = <&pinctrl_pwm1_chan0_default // 引脚控制组0,包含四个默认状态的引脚配置
&pinctrl_pwm1_chan1_default
&pinctrl_pwm1_chan2_default
&pinctrl_pwm1_chan3_default>;
clocks = <&clk_sysin>; // 指定该PWM控制器使用的时钟源为clk_sysin
clock-names = "pwm"; // 定义时钟的名称为"pwm"
st,pwm-num-chan = <4>; // 定义该PWM控制器拥有4个PWM通道
st,capture-num-chan = <2>; // 定义该PWM控制器拥有2个捕获通道
};
我们去Linux源码目录下的设备树文件中找到我们所需要的信息:
找与我们板子匹配的设备树,我这里用到的是STM32MP157A的板子,那么我就去找其对应的设备树:
由于我们这此设备树中没有找到我们所想要得到的信息,那么我们就去该文件的头文件中去找我们想要的信息:
上图我们找到了tim1的设备树节点位置,下面我们接着找到PE9复用为PWM的配置信息:
我们进入到这个xxxxx-pinctrl.dtsi中:
仿照其原有格式去寻找我们的PE9复用AF1:(‘E’, 9, AF1)我们去ctrl+F去查找我们想要的:
3、接下来修改我们的设备树,将上面的内容复制到我们的设备树中进行修改:
在根节点下添加:
/{
...
//描述风扇信息:
pwm_fan{
compatible = "wyc , pwm_fan";
status = "okay";
//描述引脚
pwms = <&pwm1 0 100 0>;
}
};
在根节点外引用我们的厂商节点进行修改:
&timers1 {
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
pwm1:pwm {
compatible = "st,stm32-pwm";
#pwm-cells = <3>;
status = "okay";
//添加pwm引脚复用:PE9复用为PWM功能&