4.3.10. LPWM 驱动调试指南
4.3.10.1. 概述
LPWM (Lite-PWM) 用于
参数
LPWM 默认
支持 频率 范围 为 1Hz - 1MHz,输出 脉冲 宽度 范围 为 1us~ 4ms。
4.3.10.2. 特点
芯片
1. 包含
2. 每个 LPWM CORE 包含 4 个 channel 输出。
3. LPWM 支持
4. 每个
5. 每个
4.3.10.3. 功能描述
典型应用
当
方式

Sensor0 配置
为主 模式( FSIN/VSYNC 为 输出),而 Sensor1 配置 为 从 模式( FSIN/VSYNC 为 输入)。 Sensor0 作为
主 设备 输出 FSYNC 信号,控制 其他 传感器 的 时间 同步,当 HOST 启动 图像 采集 时,主 设备 Sensor0 在 曝光 过程 中 输出 FSYNC 信号,触发 其他 传感器 进行 同步 采集。 Sensor1 的 FSIN/VSYNC 引脚
作为 输入,受到 来自 Sensor0 的 控制,从而 实现 了 两路 图像 传感器 的 同步 采集。
方式

将
两路 Sensor 都 配置 为 从 模式,使得 相机 的 每 一帧 采集 都 由 外部 FSYNC 信号 触发。 HOST 统一
向 Slave Sensor 发送 同步 信号,触发 其 曝光 过程,通过 配置 的 LPWM 参数,在 触发 引脚 上 输出 方波 信号,每当 两个 传感器 接收 到 触发 信号 时,它们 便 同步 采集 一帧 图像。
方式

一路 Sensor 配置
为 Slave 模式, HOST 启动 图像 采集 时,触发 引脚 上 会 输出 LPWM 配置 的 方波,当 Sensor 接收 到 trigger 信号 时 就 采集 一帧 图像。
功能原理
LPWM_CORE 模块

当 Sensor 在

4.3.10.4. 驱动代码
LPWM 代码路径
kernel/drivers/media/platform/horizon/camsys/lpwm/
内核配置
/* arch/arm64/configs/hobot_x5_soc_defconfig */
..
CONFIG_HOBOT_LPWM=m
...
DTS 节点配置
X5 PWM 及 LPWM 控制器arch/arm64/boot/dts/hobot/x5.dtsi 文件x5-evb.dts 为例,使能 lpwm0 ch0-4、lpwm1 ch1。
备注:
x5.dtsi 中
/* arch/arm64/boot/dts/hobot/x5-evb.dts */
...
&lpwm0 {
status = "okay";
/* conflict with camera pwd gpio */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpwm0_0 &pinctrl_lpwm0_1
&pinctrl_lpwm0_2 &pinctrl_lpwm0_3>;
};
&lpwm1 {
status = "okay";
pinctrl-names = "default";
/** for display backlight **/
pinctrl-0 = <&pinctrl_lpwm1_1>;
};
...
lpwm 设备树
&lpwm0:这是一个 设备 节点,表示 一个 名为 lpwm0 的 PWM 控制器。 status = "okay":表示启用 此 设备 节点,即 lpwm0 PWM 控制器 处于 启用 状态,如果 状态 设置 为 “disabled”,则 该 设备 会 被 禁用。 pinctrl-names = "default":定义了 引脚 控制 的 名称,这里 使用 了 默认 引脚 控制 配置。 pinctrl-0 = <&pinctrl_lpwm0_0 &pinctrl_lpwm0_1 &pinctrl_lpwm0_2 &pinctrl_lpwm0_3>: 这里打开 了 LPWM0 四个 channel。 指定
了 lpwm0 控制器 的 引脚 配置。这是 一个 指针 数组,指向 一系列 引脚 控制 配置(通常 是 由 pinctrl 子系统 管理 的),每个 pinctrl_lpwm0_X 表示 一个 预定 义 的 引脚 配置,用于 控制 LPWM 信号 在 物理 引脚 上 的 行为,例如 引脚 号、复用 功能、电源 域 配置 等。
4.3.10.5. 功能使用
kernel space
lpwm preobe 驱动源码
hobot_lpwm_probe 函数
static int32_t hobot_lpwm_probe(struct platform_device *pdev)
{
int32_t ret = LPWM_RET_OK;
struct hobot_lpwm_ins *lpwm;
lpwm = (struct hobot_lpwm_ins *)osal_kmalloc(sizeof(struct hobot_lpwm_ins),0);
if (IS_ERR(lpwm)) {
lpwm_err(NULL, "devm kzalloc failed!\n");
return -ENOMEM;
}
memset(lpwm, 0, sizeof(struct hobot_lpwm_ins));
ret = lpwm_preinit(pdev, lpwm);
if (ret != LPWM_RET_OK) {
return ret;
}
ret = lpwm_platform_init(pdev, lpwm);
if (ret != LPWM_RET_OK) {
goto err_disable_clk;
}
ret = pwmchip_add(&lpwm->chip);
if (ret < 0) {
lpwm_err(lpwm, "Add to Linux pwm chip failed!\n");
goto err_free_irq;
}
ret = lpwm_sysfs_create(pdev);
if (ret < 0) {
lpwm_err(lpwm, "Sysfs create failed!\n");
goto err_free_pwm_chip;
}
platform_set_drvdata(pdev, lpwm);
ret = lpwm_chip_cdev_create(lpwm);
if (ret != LPWM_RET_OK) {
goto err_free_pwm_chip;
}
lpwm_div_ratio_config(lpwm->base, 24);
glpwm_chip[lpwm->dev_idx] = lpwm;
lpwm->cim_cops = vio_get_callback_ops(&cim_ops, VIN_MODULE, COPS_9);
vin_register_device_node(VIN_LPWM, &vin_lpwm_ops);
lpwm_info(lpwm, "Probe success\n");
return ret;
err_free_pwm_chip:
pwmchip_remove(&lpwm->chip);
err_free_irq:
devm_free_irq(&pdev->dev, lpwm->irq, lpwm);
err_disable_clk:
clk_disable_unprepare(lpwm->sclk);
clk_disable_unprepare(lpwm->pclk);
osal_kfree(lpwm);
return ret;
}
驱动源码接口
1.osal_kmalloc
作用:在 hobot_lpwm_probe 中
用来 为 struct hobot_lpwm_ins 类型 的 实例 分配内存。 参数:第一个
参数 为 分配内存 的 大小,第二个 参数 通常 是 内存 分配 的 标志( 0 表示 默认)。 返回值:返回
分配 的 内存地址,若 分配 失败 返回 NULL。
2.lpwm_preinit
作用:对 LPWM 设备
进行 预 初始化。 参数:平台
设备 对象 (pdev) 和 LPWM 设备 对象 (lpwm)。 返回值:返回
一个 状态 码,若 为 LPWM_RET_OK 则 表示 初始化 成功。
3.lpwm_platform_init
作用:初始化 LPWM 驱动
需要 的 硬件资源,例如 时钟、 GPIO、 IRQ 等。 参数:平台
设备 对象 (pdev) 和 LPWM 设备 对象 (lpwm)。 返回值:返回
负值 表示 添加 失败,返回 0 表示 成功。
4.pwmchip_add
作用:为
设备 创建 一个 pwmchip 对象,将 LPWM 设备 添加 到 Linux 内核 的 PWM 子系统。 参数:&lpwm->chip 为 LPWM 设备
的 PWM 配置 结构 体。 返回值:返回
负值 表示 添加 失败,返回 0 表示 成功。
4.lpwm_sysfs_create
作用:在 sysfs 中
创建 与 LPWM 相关 的 文件,允许 用户 空间 通过 文件系统 与 驱动 交互 参数: LPWM 设备
对象 (lpwm)。 返回值:返回 LPWM_RET_OK 表示
成功,其他 表示 失败。
5.lpwm_chip_cdev_create
作用:为 LPWM 设备
创建 一个 字符 设备,允许 应用程序 通过 设备 文件 进行 访问。 参数:时钟
句柄。 返回值:返回
回调 操作 结构 体。
6.vio_get_callback_ops:
作用:获取
与 VIN(视频 输入)相关 的 回调 操作。 参数:回调
操作 结构 体 (&cim_ops),模块 标识( VIN_MODULE),操作 类型 标识( COPS_9 )。 返回值:返回
复位 控制器 的 句柄,若 获取 失败 返回 ERR_PTR。
7.vin_register_device_node
作用:将 LPWM 设备
注册 到 VIN 子系统 中,作为 视频 输入 设备。 参数: 设备
类型 标识( VIN_LPWM),回调 操作 结构 体 (&vin_lpwm_ops)。 返回值:无。
hobot_lpwm_probe 函数vin_register_device_node(VIN_LPWM, &vin_lpwm_ops) 用于
static struct vin_common_ops vin_lpwm_ops = {
.open = lpwm_open,
.close = lpwm_close,
.video_set_attr = lpwm_init,
.video_get_attr = lpwm_get_attr,
.video_set_attr_ex = lpwm_change_attr,
.video_start = lpwm_start,
.video_stop = lpwm_stop,
.video_reset = lpwm_reset,
};
user space
lpwm 配置使用说明
以 sc230ai 软件
.lpwm_attr = {
.enable = 0,
.lpwm_chn_attr = {
{ .trigger_source = 0,
.trigger_mode = 0,
.period = 100*1000,
.offset = 10,
.duty_time = 100,
.threshold = 0,
.adjust_step = 0,
},
},
};
lpwm_attr 结构
| 参数 | 说明 | 范围 | 输出 30hz,高电平 10us 参数 |
|---|---|---|---|
| offset | 与 trigger 点 |
11 | |
| duty_time | 有效 |
[0, 4000 | period) us | 9 |
| period | 周期,实际 |
[1, 1000000) us | 33332 |
| threshold | 缓慢 |
[0, 65535] us | 0 |
| adjust_step | 每次 |
[0, 15] | 0 |
| trigger_source | 触发 |
[0, 10] | |
| trigger_mode | 触发 |
[0, 1] |
常见

公式
Period = 1000000 / fps
Offset = 100000 - Period*fps
lpwm 触发方式
软件
触发: trigger_mode = 0 ,代表 内部 软件 触发,配置 软件 触发 后, LPWM 驱动 将 自动 提供 基于 hrtimer 的 周期 为 1s 软件 trigger。本质 就是 1s 去 写 一个 LPWM 寄存器 (LPWM_SW_TRIG),让 LPWM 重新 按照 配置 输出 方波。 硬件
触发: trigger_mode = 1 ,代表 代表 外部 触发,需要 外接 一个 PPS (pulse per second) 信号, LPWM 收到 PPS 信号 后,硬件 会 按照 软件 的 配置,输出 方波。每 收到 一个 PPS 信号, LPWM 都 会 按照 配置,重新 出波。 外部
触发 需要 配置 trigger_source,外部 触发 源 可以 按照 数值 配置 以下 触发 源:
| trigger_source 的 |
对应 |
说明 |
|---|---|---|
| 0-3 | pad_trigger_in | 硬件 IO 输入 PPS,软件 |
| 4 | enet_ptp_pps | 预留 |
| 5 | sw_trigger_in | 软件 |
| 6 | gps_trigger_in (TIME_SYNC2) | 硬件 IO 输入 PPS |
| 7 | mcu_trigger_in (TIME_SYNC1) | 硬件 IO 输入 PPS |
| 8 | time_sync2_in (TIME_SYNC3) | 硬件 IO 输入 PPS |
| 9 | time_sync3_in (TIME_SYNC4) | 硬件 IO 输入 PPS |
| 10 | camera_1sec_pulse_out | SIF 模块 |
lpwm 映射关系
lpwm pin name 与 pad_trigger_in_x 映射
| LPWM0 | LSIO_SPI5_SCLK | pad_trigger_in_0 |
|---|---|---|
| LSIO_SPI5_SSN | pad_trigger_in_1 | |
| LSIO_SPI5_MISO | pad_trigger_in_2 | |
| LSIO_SPI5_MOSI | pad_trigger_in_3 | |
| LPWM1 | LSIO_SPI3_SCLK | pad_trigger_in_0 |
| LSIO_SPI3_SSN | pad_trigger_in_1 | |
| LSIO_SPI3_MISO | pad_trigger_in_2 | |
| LSIO_SPI3_MOSI | pad_trigger_in_3 |
查看 evb_x5 原理图, MIPI0 接口
&lpwm0 {
status = "okay";
/* conflict with camera pwd gpio */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpwm0_0 &pinctrl_lpwm0_1
&pinctrl_lpwm0_2 &pinctrl_lpwm0_3>;
};
&vin_vcon0 {
status = "okay";
/* camera sensor
* reset gpio: AON_GPIO0_00: 498
* pwd gpio: LSIO_GPIO1_00: 347
*/
pinctrl-names = "default";
pinctrl-0 = <&aon_gpio_0>;
gpio_oth = <498>; //reset gpio
bus = <4>; //i2c4
lpwm_chn = <0>; //open lpwm0 - channel0
};
重点
lpwm0 :这是
一个 引用 节点,指 的 是 名为 lpwm0 的 硬件 模块。 pinctrl-0 (lpwm): 这个
属性 指定 了 与 lpwm0 设备 相关联 的 具体 引脚 控制 配置( pinmux 配置) pinctrl_lpwm0_0: 配置
节点 属性,配置 引脚 为 LSIO_SPI5_SCLK,引脚 复用 属性 为 Lite PWM0 output。
pinctrl_lpwm0_0: pinctrl_lpwm0_0 { horizon,pins = < LSIO_SPI5_SCLK LSIO_PINMUX_2 BIT_OFFSET8 MUX_ALT2 &pconf_pwm_1v8 >; };
vin_con0 :名为 vin_vcon0 的
视频 输入 控制 节点。 lpwm_chn:选择
启用 当前 lpwm 的 通道,通道 0 则 对应 lpwm 的 映射 引脚 为 LSIO_SPI5_SCLK。
当
sysfs 节点调试
在
查看 x5.dtsi 中 关于 LPWM 控制器
lpwm0: lpwm@34100000 {
compatible = "hobot,hobot-lpwm";
status = "disabled";
reg = <0x34100000 0x10000>;
lpwm-int-status = <&lsio_sys_con 0x0>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&hpsclks X5_LSIO_LPWM0_CLK>, <&hpsclks X5_LSIO_LPWM0_PCLK>;
clock-names = "lpwm_sclk", "lpwm_pclk";
#pwm-cells = <2>;
resets = <&socrst LSIO_LPWM0_RESET>;
};
root@buildroot:~# cat /sys/class/pwm/pwmchip2/device/uevent
DRIVER=hobot-lpwm
OF_NAME=lpwm
OF_FULLNAME=/soc/a55_apb0/lpwm@34100000
OF_COMPATIBLE_0=hobot,hobot-lpwm
OF_COMPATIBLE_N=1
OF_ALIAS_0=lpwm0
MODALIAS=of:NlpwmT(null)Chobot,hobot-lpwm
可以hobot-lpwm, DTS 中 lpwm0 的
root@buildroot:/sys/class/pwm# cd pwmchip2
root@buildroot:/sys/class/pwm/pwmchip2# ls
device export npwm power subsystem uevent unexport
device: 这是
一个 指向 设备 的 符号 链接,它 通常 链接 到 实际 的 硬件 设备 节点。通过 访问 该 文件,系统 可以 获取 或 修改 与 该 设备 相关 的 属性。 npwm: 指
当前 lpwm 所 包含 的 channel 数量,一般 为 4 。 echo:户
可以 通过 向 export 文件 写入 通道 的 编号 来 将 其 导出 到 /sys/class/pwm/pwmchip2/pwmX 目录( X 是 LPWM 通道 的 编号)。例如, echo “0~3” > unexport 注销 某个 channel,仅 允许 每个 channel 申请 一次,再次 申请 会 返回 BUSY。 power:该
文件 提供 了 与 设备 电源 管理 相关 的 信息。它 可以 包含 关于 设备 的 电源 状态 的 详细信息,比如 是否 启用 节能 模式、是否 开启 了 电源 等。 subsystem:该
目录 是 指向 该 LPWM 设备 所属 的 子系统 的 符号 链接。子系统 是 Linux 中 的 设备 管理 层次结构 的 一部分,表示 该 设备 所属 的 类别。 uevent:该
文件 用于 管理 udev(设备 管理器)事件,它 通常 用于 向 系统 通知 设备 的 变化。 unexport:该
文件 允许 用户 通过 写入 来 取消 导出 某个 LPWM 通道,如果 某个 LPWM 通道 已经 被 导出(通过 export 文件),则 用户 可以 通过 向 unexport 文件 写入 该 通道 的 编号 来 取消 导出,从而 使该 LPWM 通道 不再 可用。
可以
申请
注册 lpwm0 通道:
root@buildroot:/sys/class/pwm/pwmchip2# echo 0 > export
root@buildroot:/sys/class/pwm/pwmchip2# cd pwm0
设置 周期 为 30hz:
root@buildroot:/sys/class/pwm/pwmchip2/pwm0# echo 33333000 > period
设置 占空比 为 0.3%:
root@buildroot:/sys/class/pwm/pwmchip2/pwm0# echo 100000 > duty_cycle
使能 lpwm 输出
或 关闭
root@buildroot:/sys/class/pwm/pwmchip2/pwm0# echo 1 > enable
root@buildroot:/sys/class/pwm/pwmchip2/pwm0# echo 0 > enable
硬件调试
查看 evb x5 原理图,使用 lpwm0 通道 0 ,对应

对应

运行 sample 时,使用

示波器
4.3.10.6. 常见问题
Q: 如果源 trigger 一段时间后,源停止 trigger, LPWM 还会输出方波吗?
A : 会
Q:lpwm trigger 与中断机制
A :lpwm 发送给 cim 的