首页 > 系统相关 >Linux下PWM子系统

Linux下PWM子系统

时间:2024-07-12 17:41:26浏览次数:15  
标签:PWM struct int chip Linux device pwm 子系统

1 pwm子系统框架

image

内核态分为:

pwm core:pwm_chip的添加删除,pwm_class类pwm_chip/pwm_device的sysfs创建。

pwm driver:pwm_chip对象实例,注册添加到pwm core。
	pwm_chip可以包含一个或多个pwm_device,每个pwm_device通过设置不同pwm_state来达到目的。

1.1 源码结构

drivers/pwm/
	core.c //pwm子系统核心。
	sysfs.c//pwm子系统的pwm_class注册,pwm_chip属性,pwm_device属性等定义。
	pwm-imx.c//imx的pwm_chip驱动。

image

我已经编译进vmlinux了,可以看到built-in.oMakefile如下:

image

Kconfig如下,我的内核.config配置选中了PWM和PWM_IMX,因此编译进了内核镜像。

image

image

1.2 数据结构

1.2.1 pwm_chip

是对一个pwm控制器的抽象。

struct pwm_chip {
    struct device *dev;
    const struct pwm_ops *ops;
    int base;
    unsigned int npwm;//pwm控制器的pwm数量。
    struct pwm_device * (*of_xlate)(struct pwm_chip *pc,
                    const struct of_phandle_args *args);
    unsigned int of_pwm_n_cells;
    /* only used internally by the PWM framework */
    struct list_head list;
    struct pwm_device *pwms;
}; //include/linux/pwm.h

1.2.2 pwm_ops

pwm控制器的操作接口。

struct pwm_ops {
	int (*request)(struct pwm_chip *chip, //请求 PWM
	struct pwm_device *pwm);
	void (*free)(struct pwm_chip *chip, //释放 PWM
	struct pwm_device *pwm);
	int (*config)(struct pwm_chip *chip, //配置 PWM 周期和占空比
	struct pwm_device *pwm,
	int duty_ns, int period_ns);
	int (*set_polarity)(struct pwm_chip *chip, //设置 PWM 极性
	struct pwm_device *pwm,
	enum pwm_polarity polarity);
	int (*enable)(struct pwm_chip *chip, //使能 PWM
	struct pwm_device *pwm);
	void (*disable)(struct pwm_chip *chip, //关闭 PWM
	struct pwm_device *pwm);
	struct module *owner;
};

1.2.3 pwm_state

pwm_state就是控制占空比控制转速,亮度参数。

struct pwm_state {
    unsigned int period; //pwm的周期,单位ns。
    unsigned int duty_cycle; //占空比duty_cycle,单位ns。
    enum pwm_polarity polarity;//PWM_POLARITY_NORMAL表示高电平持续duty_cycle,
    //然后是低电平持续剩余时间。PWM_POLARITY_INVERSED表示低电平持续duty_cycle,然后是高电平持续剩余时间。
    bool enabled; //是否使能
};

1.3 API

api声明见linux\include\linux\pwm.h,实现linux\drivers\pwm\core.c

1.3.1 pwmchip_add

pwm子系统注册一个pwm_chip

int pwmchip_add(struct pwm_chip *chip);

pwmchip_add
	pwmchip_add_with_polarity
		->pwm_ops_check   //检查pwm_ops是否支持apply等。
		->alloc_pwms     //为pwm_chip的pwm_device分配allocated_pwms。
		->//初始化每个pwm_device,并加入pwm_tree。
		->pwmchip_sysfs_export
			->pwmchip_sysfs_export //创建pwm_class类设备pwmchpX,位于/sys/class/pwm/pwmchipX。

image

1.3.2 pwmchip_remove

int pwmchip_remove(struct pwm_chip *chip);

删除一个pwm_chip

image

1.3.3 pwm_request

请求 PWM。

struct pwm_device *pwm_request(int pwm, const char *label)

image

image

可以看到就是调用具体pwm示例的request函数。

1.3.4 pwm_free

释放 PWM。

void pwm_free(struct pwm_device *pwm)

image

1.3.5 pwm_config

配置 PWM 周期和占空比,操作具体pwm实例。

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)

image

1.3.6 pwm_set_polarity

设置 PWM 极性。

int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)

image

1.3.6 pwm_enable

image

1.3.7 pwm_disable

image

2 pwm驱动实例

I.MX6ULL 有 8 路 PWM 控制器。这 8 路 PWM 都属于I.MX6ULL 的 AIPS-1域,但是在设备树imx6ull.dtsi中 分为了两部分,PWM1~PWM4 在一起,PWM5~PWM8 在一起。以pwm3为例:

2.1 dts描述

打开imx6ull.dtsi:可以看到pwm3的描述:

pwm3: pwm@02088000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x02088000 0x4000>;
	interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM3>,
	<&clks IMX6UL_CLK_PWM3>;
	clock-names = "ipg", "per";
	#pwm-cells = <2>;
};

关 于I.MX6ULLPWM dts节点描述参考对应的绑定文档 : Documentation/devicetree/bindings/pwm/ imx-pwm.txt

GPIO1_IO04 这里作为PWM3的输出引脚,所以我们需要在设备树里面添加 GPIO1_IO04 的引脚信息以及PWM3控制器对应的节点信息:

打开 imx6ull-alientek-emmc.dts:,添加iomux配置信息:

pinctrl_pwm3: pwm3grp {
	fsl,pins = <MX6UL_PAD_GPIO1_IO04__PWM3_OUT 0x110b0>;
};
&pwm3 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pwm3>;
	status = "okay";
};

2.2 使能PWM驱动

image

.config中已经使能了,但是为了学习, 我们还是需要知道怎么使能。

image

-> Device Drivers
    -> Pulse-Width Modulation (PWM) Support
        -> <*> i.MX PWM support

2.3 PWM 背光设置

linux 内核里面关于 backlight(背光)的绑定文档,路径为 Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt,此文档描述了如何创建 backlight 节点来使用linux内核自带的pwm背光驱动。

compatible:内容必须为“pwm-backlight”,通过这个可以匹配到内核自带的 PWM 背光驱
动,驱动文件为 drivers/video/backlight/pwm_bl.c,这里就不去分析驱动源码了。

pwms:此属性指定背光使用哪一路 PWM,以及 PWM 相关的属性。

brightness-levels:背光等级数组,范围 0~255,对应占空比为 0%~100%。数组内的值必须
从 0 开始,也就是 0%占空比,最后一个值必须是 255,也就是 100%占空比。数组中间值的个
数以及值大小可以自行定义。

default-brightness-level:默认的背光等级,也就是 brightness-levels 属性中第几个值,注意
这里是数索引编号,不是具体的数值!

power-supply:支持的电压,此属性可以不需要
backlight {
    compatible = "pwm-backlight";
    pwms = <&pwm1 0 5000000>;// PWM 周期为 5000000ns,频率为 200Hz
    brightness-levels = <0 4 8 16 32 64 128 255>;
    default-brightness-level = <7>;
    status = "okay";
};

2.4 驱动源码分析

2.4.1 probe过程

2.4.1.1 imx_chip

image

定义了imx_chip,包装了pwm_chip结构。

image

probe时,先分配内存,从dts获取per, ipg等时钟信息,设置pwm的ops为imx_pwm_ops。最后pwmchip_add注册进pwm子系统。注意这里有一个of_id->data,对应如下:可以看到有v1,v2两2版本,到时候会被ops中的函数调用。

image

同理,驱动卸载最后调用pwmchip_remove注销pwm。

image

2.4.2 imx_pwm_ops

image

2.4.2.1 imx_pwm_config

配置 PWM 周期和占空比。根据dts描述我们使用的是v2。

image

image

image

PWMv2会有4 word的采样fifo, 为了避免采样FIFO溢出,当pwm关闭时,对所有采样FIFO进行软件复位。当pwm使能后处于工作中,要等待完整的 PWM 周期以保证pwm空闲。

然后设置PWM 周期period_cycles,和占空比duty_cycles

最后调用writel写入寄存器。

image

2.4.2.2 imx_pwm_enable

控制MX3_PWMCR寄存器,使能关闭开关。

image

image

2.4.2.3 imx_pwm_disable

image

3 基于pwm sysfs测试

alpha开发板 JP2 排针上的 GPIO_4(GPIO1_IO04)引脚连接到 示波器上。等下看pwm信号效果。

可以看到一共8 路 PWM 控制器:

image

我们使用的pwm3,对应出 pwmchip2, 导出chip2通道的0设备文件:

echo 0 > /sys/class/pwm/pwmchip2/export

执行完成会在pwmchip2 目录下生成一个名为“pwm0”的子目录:

image

echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable #使能pwm3
echo 50000 > /sys/class/pwm/pwmchip2/pwm0/period #设置周期值,单位为 ns,比如 20KHz 频率的周期就是 50000ns
echo 10000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle #20%占空比

image

总结:

导出chip1通道的0设备文件:echo 0 > /sys/class/pwm/pwmchip1/export
配置chip1通道0的周期: echo 10000000 > /sys/class/pwm/pwmchip1 /pwm0/period
配置chip1通道0的占空比:echo 4000000 >/sys/class/pwm/pwmchip1/pwm0/duty_cycle
配置片chip通道0使能: echo 1 > /sys/class/pwm/pwmchip1/pwm0/enable
配置片chip通道0禁能: echo 0 > /sys/class/pwm/pwmchip1/pwm0/enable
取消导出片chip通道0设备文件: echo 0 >/sys/class/pwm/pwmchip1/unexport

标签:PWM,struct,int,chip,Linux,device,pwm,子系统
From: https://www.cnblogs.com/fuzidage/p/18299086

相关文章

  • Linux捣鼓记录:debian12解决用户无法执行sudo,提示不是 sudoers 文件
    问题:dalong@debian:~$sudoaptupdate[sudo]dalong的密码:dalong不是sudoers文件。当你尝试使用sudo命令并收到"dalong不是sudoers文件"的错误信息时,这意味着用户dalong没有被配置为可以使用sudo命令。在Debian和其他基于Debian的系统中,sudo的权限是由......
  • Rocky Linux/Redhat8运行Calibre2022报错:Software tree is for environment VCO=aoj
    运行出现了错误:virserver.tclerror:ERROR:CurrentexecutionenvironmentisVCO=aok.SoftwaretreeisforenvironmentVCO=aoj。即calibre软件版本为aoj,但当前的环境是aok。从官网查询calibre的roadmap:http://calibre.mentorcloudservices.com/docs/Calibre_OS_Roadmap.......
  • Linux 外挂磁盘
    1.查看PC磁盘lsblk-f结果:NAMEFSTYPELABELUUIDMOUNTPOINTsdb└─sdb1ext4b5ae9dca-7e36-4ed9-8090-08415f9bb5......
  • 嵌入式linux使用usb接口,共享windows网络
    【RNDIS】嵌入式linux使用usb接口,共享windows网络内核配置CONFIG_USB_GADGETFS=mCONFIG_USB_ETH=mCONFIG_USB_ETH_RNDIS=yusb接口工作在device模式,我理解使用otg或者device模式都可以。数据流以太网<----->windows/linux网卡<----->usb接口<----->嵌入式Linux系统......
  • TCP,Linux下清除空闲连接功能
    #include<iostream>#include<ctime>structConnection{ intsockfd; time_tlastActiveTime; //构造函数 Connection(intfd):sockfd(fd),lastActiveTime(time(nullptr)){} //更新最后活动时间 voidupdateActivity() { lastActiveTime=time(......
  • 【Linux】02.shell命令及其运行原理
    一、概念与功能广义上的Linux操作系统分为Linux内核和Linux外壳。内核部分就是我们实际的Linux操作系统,我们称之为核心(kernel)。我们一般用户,不擅长也不能直接使用kernel,而是通过kernel的外壳程序,也就是所谓的shell来与kernel沟通。那么如何理解?为什么不能直接使用kerne......
  • linux-Rsyslog自定义配置json模板
    配置日志接收模板和转发参考:https://www.cnblogs.com/xwupiaomiao/p/17565418.html自定义模板配置文件在主配置文件中添加(rsyslog.conf)include(file=“/etc/rsyslog.d/*.conf”mode=“optional”)方案一在/etc/rsyslog.d/下创建一个配置文件ct3a1.conf#日志模板......
  • Linux下WIFI驱动使用
    1WIFI驱动编译初体验一般WIFI有2种接口:USB和SDIO。例如USBWIFI使用的芯片为RTL8188EUS或RTL8188CUS,SDIO接口的WIFI使用芯片为RTL8189FS,如下图:RTL8189和RTL8188都是realtek公司出品的WIFI芯片,WIFI芯片原厂一般会整包提供。1.1向Linux内核添加WIFI驱动realt......
  • 环境部署之在 Linux 服务器上搭建和部署 Python 环境
    背景说明在企业工作中,自动化测试框架落地肯定会集成到Jenkins服务器上做持续集成测试,自动构建以及发送结果到邮箱,实现真正的无人值守测试。不过Jenkins搭建一般都会部署在公司的服务器上,不会在私人电脑里,而服务器大部分都是Linux操作系统的。如果要在Linux上的Jenkins服......
  • Linux捣鼓记录:debian配置自动补全、ll命令别名、配置sbin命令、jdk命令
    一、配置自动补全、ll命令别名配置在/etc/bash.bashrc,实现全局用户自动补全,ll命令别名sudonano/etc/bash.bashrc有一段类似下面的文字被注释,取消注释#enablebashcompletionininteractiveshellsif!shopt-oqposix;thenif[-f/usr/share/bash-completion/bas......