linux pwm 开发指南 1 概述 1.1 编写目的 介绍 pwm 模块的详细设计方便相关人员进行 pwm 模块的代码设计开发。
1.2 使用范围 适用于 linux-3.10,linux-4.4 和 linux-4.9 内核,linux-5.4 内核。
1.3 相关人员 pwm 驱动的开发人员/维护人员等
2 术语及概念 2.1 术语定义及缩略语 术语 解释说明
sunxi 指 allwinner 的一系列 soc 硬件平台
频率 pwm 的频率决定了所模拟电平的平滑度(逼真度),人耳感知的频率范围为 20hz-16khz,注意 pwm 的频率不要落在这个区间
占空比 决定了一个周期内 pwm 信号高低的比例,进而决定了一个周期内的平均电压,也就是所模拟的电平的电压
极性 决定了是高占空比的信号输出电平高,还是低占空比信号输出电平高。假设一个信号 的占空比为 100%,如果为正常极性,则输出电平最大,如果为翻转的极性,则输出 电平为 0
开关 控制 pwm 信号是否输出
pwm对 电机等硬件需要两路脉冲信号来控制其正常运转,一般两路极性相关,频率,占空比 参数相同的 pwm 构成一个 pwm 对
pwm死区控制时间 大功率电机,变频器等由大功率管,igbt 等元件组成 h 桥或 3 相桥,每个桥的上 半桥和下半桥是绝对不能导通的,在 pwm 信号驱动这些元件时,往往会由于没有延 迟而造成未关断某路半桥,这样会造成功率元件的损坏,在 pwm 中加入死区时间的 控制即是让上半桥关断后,自动插入一个事件,延迟后再打开下半桥
2.2 概念阐述 脉冲宽度调制(pwm)是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的 使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。
pwm 模块属于 pwm 子系统,会调用 pwm 子系统的相关接口(详情可以查看 pwm 子系 统知识)
3 模块描述 3.1 模块功能
图 3-1: 模块功能
不同平台上拥有不同个数的 pwm 通道,其中两个为一个 pwm 对(平台通道数不相同,pwm 对也就不相同,具体细节可以查看对应方案的 spec)。其中 pwm 具有以下特点:
• 支持脉冲,周期和互补对输出 • 支出捕捉输入
• 带可编程死区发生器,死区时间可控
• 0-24m/100m 输出频率范围。0%-100% 占空比可调,最小分辨率 1/65536
• 支持 pwm 输出和捕捉输入产生中断
3.2 模块位置 pwm 模块属于硬件驱动层,直接与硬件通信
3.3 模块配置 3.3.1 linux-4.9 在 linux-4.9 中, 在命令行中进入内核根目录,执行 make arch=arm(arm64) menuconfig 进入配置主界面,并按以下步骤操作:
首先,选择 device drivers 选项进入下一级配置,如下图所示:
图 3-2: device drivers
选择 pulse-width modulation (pwm) support 进入下一步配置,如下图所示:
图3-3: pulse-width modulation (pwm) support
3.选择 sunxi pwm select 进入下一步配置,如下图所示:
图3-4: sunxi pwm select
4.选择 sunxi enhance pwm support 配置
图 3-5: sunxi enhance pwm support
在 4.9 内核选择该配置,选择的是对应目录中的 pwm-sunxi-new.c 文件。也可以有以下配置; 在第 3 步中直接选择 allwinner pwm support 选项,选择的是对应目录中的 pwm-sun4i.c 文件
在第 4 步中选择 sunxi pwm support 选项,选择的是对应目录中的 pwm-sunxi.c 文件
3.3.2 linux-5.4 linux5.4 平台中, 在命令行中进入内核根目录,执行./build.sh menuconfig 进入配置主界面, 并按以下步骤操作:
首先,选择 device drivers 选项进入下一级配置,如下图所示:
图 3-6: device
选择 pulse-width modulation (pwm) support 进入下一步配置,如下图所示
图 3-7: pulse-width modulation (pwm) suppor
选择 sunxi pwm select 进入下一步配置,如下图所示:
图3-8: sunxi pwm select
选择 sunxi pwm group support 配置
图3-9: sunxi pwm group support
3.4 设备树配置 3.4.1 linux-4.9 pwm 模块在设备树中的配置如下所示:
pwm: pwm@0300a000 {
ompatible = allwinner,sunxi-pwm;
reg = ; //寄存器地址配置
pwm-number = ; //pwm的个数
pwm-base = ; //pwm的起始序号
pwms = , ;
};
s_pwm: s_pwm@0300a000 {
compatible = allwinner,sunxi-s_pwm;
reg = ;
pwm-number = ;
pwm-base = ;
pwms = ;
};
注意,如果在模块配置中选择了 sunxi pwm support 选项 (具体参数可以查看相关源文件),则 需要配置以下设备树:
pwm0: pwm0@01c23400 {
compatible = allwinner,sunxi-pwm0;
pinctrl-names = active, sleep;
reg_base = ;
reg_peci_offset = ;
reg_peci_shift = ;
reg_peci_width = ;
reg_pis_offset = ;
reg_pis_shift = ;
reg_pis_width = ;
reg_crie_offset = ;
reg_crie_shift = ;
reg_crie_width = ;
reg_cfie_offset = ;
reg_cfie_shift = ;
reg_cfie_width = ;
reg_cris_offset = ;
reg_cris_shift = ;
reg_cris_width = ;
reg_cfis_offset = ;
reg_cfis_shift = ;
reg_cfis_width = ;
reg_clk_src_offset = ;
reg_clk_src_shift = ;
reg_clk_src_width = ;
reg_bypass_offset = ;
reg_bypass_shift = ;
reg_bypass_width = ;
reg_clk_gating_offset = ;
reg_clk_gating_shift = ;
reg_clk_gating_width = ;
reg_clk_div_m_offset = ;
reg_clk_div_m_shift = ;
reg_clk_div_m_width = ;
reg_pdzintv_offset = ;
reg_pdzintv_shift = ;
reg_pdzintv_width = ;
reg_dz_en_offset = ;
reg_dz_en_shift = ;
reg_dz_en_width = ;
reg_enable_offset = ;
reg_enable_shift = ;
reg_enable_width = ;
reg_cap_en_offset = ;
reg_cap_en_shift = ;
reg_cap_en_width = ;
reg_period_rdy_offset = ;
reg_period_rdy_shift = ;
reg_period_rdy_width = ;
reg_pul_start_offset = ;
reg_pul_start_shift = ;
reg_pul_start_width = ;
reg_mode_offset = ;
reg_mode_shift = ;
reg_mode_width = ;
reg_act_sta_offset = ;
reg_act_sta_shift = ;
reg_act_sta_width = ;
reg_prescal_offset = ;
reg_prescal_shift = ;
reg_prescal_width = ;
reg_entire_offset = ;
reg_entire_shift = ;
reg_entire_width = ;
reg_active_offset = ;
reg_active_shift = ;
reg_active_width = ;
};
pwm 模块在 sys_config.fex 的配置如下所示:
[pwm0]
pwm_used = 1
pwm_positive = port:pb2
[pwm0_suspend]
pwm_positive = port:pb2
3.4.2 linux-5.4 pwm 模块在设备树中的配置如下所示:
pwm: pwm@2000c00 {
#pwm-cells = ;
compatible = allwinner,sunxi-pwm;
reg = ;
clocks = ;
resets = ;
pwm-number = ;
pwm-base = ;
sunxi-pwms = , , , , ,
, , ;
};
pwm0: pwm0@2000c10 {
compatible = allwinner,sunxi-pwm0;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm1: pwm1@2000c11 {
compatible = allwinner,sunxi-pwm1;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm2: pwm2@2000c12 {
compatible = allwinner,sunxi-pwm2;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm3: pwm3@2000c13 {
compatible = allwinner,sunxi-pwm3;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm4: pwm4@2000c14 {
compatible = allwinner,sunxi-pwm4;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm5: pwm5@2000c15 {
compatible = allwinner,sunxi-pwm5;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm6: pwm6@2000c16 {
compatible = allwinner,sunxi-pwm6;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
pwm7: pwm7@2000c17 {
compatible = allwinner,sunxi-pwm7;
pinctrl-names = active, sleep;
reg = ;
reg_base = ;
};
在板级目录下的配置:
pwm3_pin_a: pwm3@0 {
pins = pb0;
function = pwm3;
drive-strength = ;
bias-pull-up;
};
pwm3_pin_b: pwm3@1 {
pins = pb0;
function = gpio_in;
bias-disable;
};
pwm7_pin_a: pwm7@0 {
pins = pd22;
function = pwm7;
drive-strength = ;
bias-pull-up;
};
pwm7_pin_b: pwm7@1 {
pins = pd22;
function = gpio_out;
};
&pwm3 {
pinctrl-names = active, sleep;
pinctrl-0 = ;
pinctrl-1 = ;
status = okay;
};
&pwm7 {
pinctrl-names = active, sleep;
pinctrl-0 = ;
pinctrl-1 = ;
status = okay;
};
具体通道配置按照需求进行配置.
3.5 源码结构 pwm 驱动的源代码位于内核的 drivers/pwm 目录下,具体的路径如下所示:
3.5.1 linux-4.9 drivers/pwm/
├── pwm-sunxi-new.c // sunxi enhance pwm support对应的pwm驱动
├── pwm-sunxi.c // sunxi pwm support对应的pwm驱动
├── pwm-sun4i.c // allwiner pwm support对应的pwm驱动
├── sysfs.c //pwm子系统的文件系统相关文件
├── core.c //pwm子系统的核心文件
3.5.2 linux-5.4 drivers/pwm/
├── pwm-sunxi-group.c // sunxi group pwm support对应的pwm驱动
├── sysfs.c //pwm子系统的文件系统相关文件
├── core.c //pwm子系统的核心文件
3.6 调试接口 可以直接在 linux 内核中调试 pwm 模块,具体如下: 进入/sys/class/pwm 目录,该目录是 linux 内核为 pwm 子系统提供的类目录,遍历该目录:
/sys/class/pwm # ls
pwmchip0
可以看到,上述 pwmchip0 就是我们注册的 pwm 控制器,进入该目录,然后遍历该目录:
/sys/class/pwm # cd pwmchip0/ /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # ls device export npwm subsystem uevent unexport
其中 npwm 文件储存了该 pwm 控制器的 pwm 个数,而 export 和 unexport 是导出和删除某 个 pwm 设备的文件,下面演示导出 pwm1。
/sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # cat npwm 2 /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # echo 1 > export /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # ls device export npwm pwm1 subsystem uevent unexport
可以看到目录中多出 pwm1 目录,进入该目录,遍历:
/sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # cd pwm1/ /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0/pwm1 # ls capture duty_cycle enable period polarity uevent
该目录中,enable 是使能 pwm,duty_cycle 是占空比,period 是周期,polarity 是极性,可 以配置相关的 pwm 并且使能:
/sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0/pwm1 # echo 1000000000 > period /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0/pwm1 # echo 500000000 > duty_cycle /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0/pwm1 # echo normal > polarity /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0/pwm1 # echo 1 > enable
如果相关引脚接上了示波器等,可以看到波形。最后返回上层目录,删除该 pwm 设备:
/sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0/pwm1 # cd .. /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # ls device export npwm pwm1 subsystem uevent unexport /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # echo 1 > unexport /sys/devices/platform/soc/1c23400.pwm/pwm/pwmchip0 # ls device export npwm subsystem uevent unexport
连接器的组装因素分析
2021真无线耳机推荐,必须了解的真无线蓝牙耳机
一种以DSP芯片为核心的通用型数字变频器系统设计方案概述
融合一二代优点 日本开发出第三代OLED荧光材料
酷派集团发布公告,宣称公司与浦发贷款纠纷案达成和解
Linux PWM开发指南
几种常用单片机介绍
几个方面有针对性地解决当下国内智慧城市建设中的各种问题
LVDS技术原理和设计简介
电源模块布局中考虑元器件的寄生参数
分析仪器CAN网络通信设计
锤子M1L猛降600元,急着清库存?
电动助力转向系统用扭矩传感器分类_各类型电动助力转向系统用扭矩传感器介绍
高通发布10nm骁龙835处理器,三星FinFET打造
Leader发布“养成系”冰箱,占地可大可小
2019年彩电市场将恢复性增长 预计零售量规模将达4851万台
清华与新思的往事
韩国2月起推出无人驾驶公交车服务
解决方案 | 传感精灵护航,电路板的印刷机之旅
人工智能在体育产业中的应用