Edit online

PWM 配置

17 Dec 2024
Read time: 8 minute(s)

内核配置

  1. 在 SDK 根目录下,执行下列命令,进入 kernel 的功能配置界面:
    make kernel-menuconfig

    或使用简写命令

    make km
  2. 在内核配置界面,按如下选择:
    Linux
        Device Drivers  --->
            [*] Pulse-Width Modulation (PWM) Support  --->
                <*>   ArtInChip PWM support
                <*>   ArtInChip EPWM support
    
  3. 如需设置 PWM 模块的背光控制功能,执行下列配置,否则可跳过。

    在 SDK 根目录下执行 make kernel-menuconfigmake me,进入 kernel 的功能配置,按如下选择:

    Linux
        Device Drivers  --->
            Graphics support  --->
                Backlight & LCD device support  --->
                    <*> Lowlevel Backlight controls
                    <*>   Generic PWM based Backlight Driver
    
  4. 如使用 logo 功能,须在 Boot 阶段打开屏幕背光,否则可跳过。

    在 SDK 根目录下执行 make kernel-menuconfigmake me,进入 kernel 的功能配置,按如下选择:

    U-Boot
        Device Drivers  --->
            [*] Enable support for pulse-width modulation devices (PWM)
            [*]   Enable support for ArtInChip PWM
            Graphics support  --->
                [*] Generic PWM based Backlight Driver
    

DTS 参数配置

PWM 驱动支持从 DTS 中配置的自定义参数,如下表所示:

1. PWM 自定义参数
参数名称 类型 取值范围 功能说明
mode String up/down/up-down-count 配置增减模式
tb-clk-rate Integer (0, 24000000) 时基计数器的工作时钟
action0 String none/low/high/inverse 多个关键时点的触发行为
action1 String none/low/high/inverse 多个关键时点的触发行为
default-level Integer [0, 1] 默认/初始电平
注:

为了方便表达,所有参数名称都省略了前缀 “aic,”。

表中 action0 和 action1 四种取值的含义,定义如下:

2. action0 和 action1 取值含义
Action 类型 行为描述
none 不做任何变化,保持之前的输出电平
low 跳变为 0 电平
high 跳变为 1 电平
inverse 跳变为反向的电平,比如从 0 跳变为 1

时钟配置

PWM 模块涉及时钟的衍生关系:


pwm_clk_tree

1. PWM 模块的时钟衍生关系图

EWM 模块涉及时钟的衍生关系:


epwm_clk_tree

2. EPWM 模块的时钟衍生关系图

其中,前两个时钟在 PWM 控制器的节点中配置,后两个时钟在 Board 中的 PWM 子节点(对应通道)中配置。

注:
容易混淆的 sysclk:
  • PWM 驱动中,按照惯例将父时钟称作 sysclk,即上图的 PLL INT1。

  • PWM 硬件 spec 中,将上图中的 PWM Clk 称作 sysclk

D211 配置

common/d211.dtsi 中的参数配置:

pwm: pwm@19240000 {
    compatible = "artinchip,aic-pwm-v1.0";
    reg = <0x0 0x19240000 0x0 0x1000>;
    interrupts-extended = <&plic0 90 IRQ_TYPE_LEVEL_HIGH>;
    #pwm-cells = <3>;
    clocks = <&cmu CLK_PWM>, <&cmu CLK_PLL_INT1>;
    clock-names = "pwm", "sysclk";
    resets = <&rst RESET_PWM>;
    clock-rate = <48000000>;
};

epwm: epwm@18200000 {
    compatible = "artinchip,aic-epwm-v1.0";
    reg = <0x0 0x18200000 0x0 0x600>, <0 0x1820F000 0x0 0x1000>;
    interrupts-extended = <&plic0 25 IRQ_TYPE_LEVEL_HIGH>;
    #pwm-cells = <3>;
    clocks = <&cmu CLK_PWMCS>, <&cmu CLK_PLL_INT1>;
    clock-names = "pwmcs", "sysclk";
    resets = <&rst RESET_PWMCS>;
    clock-rate = <48000000>;
    status = "disabled";
};

Board 配置

  • PWM 通道配置
    xxx/board.dts 中的参数配置:
    &pwm {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pwm2_pins_b>;
        /* mode: up-count, down-count, up-down-count
           action: none, low, high, inverse */
        pwm0 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            aic,rise-edge-delay = <10>;
            aic,fall-edge-delay = <10>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "low", "none", "high";
            aic,action1 = "none", "none", "none", "high", "none", "low";
            status = "disabled";
        };
    
        pwm1 {
            aic,mode = "down-count";
            aic,tb-clk-rate = <24000000>;
            aic,rise-edge-delay = <10>;
            aic,fall-edge-delay = <10>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "low", "none", "high";
            aic,action1 = "none", "none", "none", "high", "none", "low";
            status = "disabled";
        };
    
        pwm2 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "low", "none";
            aic,action1 = "none", "none", "none", "low", "high", "none";
            aic,default-level = <0>;
            aic,rise-edge-delay = <10>;
            aic,fall-edge-delay = <10>;
            status = "okay";
        };
    
        pwm3 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "low", "high", "none";
            aic,action1 = "none", "none", "none", "high", "low", "none";
            aic,rise-edge-delay = <10>;
            aic,fall-edge-delay = <10>;
            status = "disabled";
        };
    };
    
    &epwm {
        status = "disabled";
        pinctrl-names = "default";
        pinctrl-0 = <&epwm0_pins_a>,
                 <&epwm1_pins_a>,
                 <&epwm2_pins_a>;
        /* mode: up-count, down-count, up-down-count
        action: none, low, high, inverse */
        epwm0 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "none", "low";
            aic,action1 = "none", "high", "none", "none", "none", "low";
            status = "disabled";
        };
    
        epwm1 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "none", "low";
            aic,action1 = "none", "high", "none", "none", "none", "low";
            status = "disabled";
        };
    
        epwm2 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "none", "low";
            aic,action1 = "none", "high", "none", "none", "none", "low";
            status = "disabled";
        };
    
        epwm3 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "none", "low";
            aic,action1 = "none", "high", "none", "none", "none", "low";
            status = "disabled";
        };
    
        epwm4 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "none", "low";
            aic,action1 = "none", "high", "none", "none", "none", "low";
            status = "disabled";
        };
    
        epwm5 {
            aic,mode = "up-count";
            aic,tb-clk-rate = <24000000>;
            /*            CBD,    CBU,    CAD,    CAU,    PRD,   ZRO */
            aic,action0 = "none", "none", "none", "high", "none", "low";
            aic,action1 = "none", "high", "none", "none", "none", "low";
            status = "disabled";
        };
    };
  • 背光控制配置
    需要在 xxx/board.dts 中新增一个 backlight 节点,如下:
    backlight: backlight {
        compatible = "pwm-backlight";
        /* pwm node name; pwm device No.; period_ns; pwm_polarity */
        pwms = <&pwm 2 1000000 0>;
        brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
        default-brightness-level = <8>;
        status = "okay";
    };

    其中 “&pwm 2” 表示要使用 pwm2 通道作为背光控制用(要确认和硬件上的电路连接是一致的)。

    在屏幕 panel 节点中,需要引用 backlight:
    panel_lvds {
        compatible = "artinchip,aic-general-lvds-panel";
        data-mapping = "vesa-24";
        data-channel = "single-link1";
        backlight = <&backlight>;
        status = "okay";
        ...
    };