PWM 驱动

基于 lisa_device 框架的 PWM 设备驱动,为 ARCS 平台提供统一的 PWM 信号输出接口。

功能特性

  • 设备支持: PWM0 控制器

    • 基于 GPT0(通用定时器)实现

    • 8 个独立 PWM 通道(Channel 0-7)

    • 每个通道可配置不同的频率、占空比和极性

  • 频率控制: 智能时钟分频选择

    • 自动选择最优时钟分频(÷1/2/4/8/16/32/64/128)

    • 支持宽频率范围(取决于系统 PCLK,典型范围 12Hz-100MHz)

    • 支持在相同分频范围内连续动态调整

  • 占空比控制: 1%-99% 占空比,精度 1%

  • 极性配置: 支持正常极性(高电平有效)与反转极性(低电平有效)

  • 线程安全: 内部使用互斥锁保护,可在多线程环境中安全使用

配置选项

prj.conf 中启用驱动:

# 启用 PWM 驱动
CONFIG_LISA_PWM=y

PWM 驱动默认使用 PCLK 时钟源和 Edge Aligned 输出模式,无需额外配置。

API 接口

配置接口

int lisa_pwm_configure(lisa_device_t *dev, uint32_t channel, const lisa_pwm_config_t *config);
int lisa_pwm_get_config(lisa_device_t *dev, uint32_t channel, lisa_pwm_config_t *config);

配置 PWM 通道的属性(如极性)。

控制接口

int lisa_pwm_set(lisa_device_t *dev, uint32_t channel, uint32_t frequency_hz, uint8_t duty_cycle_percent);
int lisa_pwm_enable(lisa_device_t *dev, uint32_t channel);
int lisa_pwm_disable(lisa_device_t *dev, uint32_t channel);

使用示例

基础 PWM 输出

#include "lisa_pwm.h"

// 1. 获取 PWM 设备
lisa_device_t *pwm = lisa_device_get("pwm0");
if (!lisa_device_ready(pwm)) {
    return -1;
}

// 2. 设置频率与占空比(5kHz,50% 占空比)
int ret = lisa_pwm_set(pwm, 0, 5000, 50);
if (ret != LISA_DEVICE_OK) {
    printf("Failed to set PWM: %d\n", ret);
    return -1;
}

// 3. 启用 PWM 输出
ret = lisa_pwm_enable(pwm, 0);
if (ret == LISA_DEVICE_OK) {
    printf("PWM output started\n");
}

// 4. 停止输出
lisa_pwm_disable(pwm, 0);

配置极性

#include "lisa_pwm.h"

// 1. 获取设备
lisa_device_t *pwm = lisa_device_get("pwm0");
if (!lisa_device_ready(pwm)) {
    return -1;
}

// 2. 配置通道 0 为反转极性(低电平有效)
lisa_pwm_config_t config = {
    .polarity = LISA_PWM_POLARITY_INVERTED,
};
lisa_pwm_configure(pwm, 0, &config);

// 3. 设置频率和占空比
lisa_pwm_set(pwm, 0, 5000, 50);

// 4. 启用输出
lisa_pwm_enable(pwm, 0);

动态调整频率和占空比

#include "lisa_pwm.h"

// 1. 获取设备
lisa_device_t *pwm = lisa_device_get("pwm0");
if (!lisa_device_ready(pwm)) {
    return -1;
}

// 2. 设置初始参数并启用
lisa_pwm_set(pwm, 0, 1000, 10);  // 1kHz, 10%
lisa_pwm_enable(pwm, 0);

// 3. 动态调整占空比
lisa_pwm_set(pwm, 0, 1000, 50);  // 保持 1kHz, 调整为 50%
lisa_pwm_set(pwm, 0, 1000, 90);  // 保持 1kHz, 调整为 90%

// 4. 动态调整频率(在相同时钟分频范围内)
lisa_pwm_set(pwm, 0, 2000, 50);  // 调整为 2kHz, 50%
lisa_pwm_set(pwm, 0, 5000, 70);  // 调整为 5kHz, 70%
lisa_pwm_set(pwm, 0, 10000, 30); // 调整为 10kHz, 30%

// 5. 停止输出
lisa_pwm_disable(pwm, 0);

多通道同时使用

#include "lisa_pwm.h"

// 1. 获取设备
lisa_device_t *pwm = lisa_device_get("pwm0");
if (!lisa_device_ready(pwm)) {
    return -1;
}

// 2. 配置通道 0: 5kHz, 50% 占空比
lisa_pwm_set(pwm, 0, 5000, 50);
lisa_pwm_enable(pwm, 0);

// 3. 配置通道 1: 10kHz, 30% 占空比
lisa_pwm_set(pwm, 1, 10000, 30);
lisa_pwm_enable(pwm, 1);

// 4. 配置通道 2: 1kHz, 70% 占空比
lisa_pwm_set(pwm, 2, 1000, 70);
lisa_pwm_enable(pwm, 2);

硬件配置

引脚复用配置

PWM 驱动在初始化时会自动调用板型目录中定义的 lisa_pwm_pinmux() 函数,用于配置 PWM 通道的引脚复用。

配置位置:

  • 定义: boards/<板型名>/pinmux.c 中实现 lisa_pwm_pinmux() 函数

  • 声明: boards/<板型名>/pinmux.h 中声明 void lisa_pwm_pinmux()

  • 调用时机: PWM0 设备初始化时自动调用

示例 (参考 boards/arcs_evb/pinmux.c):

void lisa_pwm_pinmux()
{
    // 配置 PA20 为 PWM 功能(功能码 12)
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 20, 12);
}

注意:

  • 该函数由板型相关代码实现,不同板型的引脚配置可能不同

  • 只需配置实际使用的 PWM 通道引脚

  • 功能码需根据芯片手册确定

支持的通道

PWM0 控制器支持 8 个独立通道(Channel 0-7),每个通道可配置不同的频率、占空比和极性。

PWM 时钟配置对比

特性

PWM0

设备基础

基于 GPT0

通道数

8 个独立通道

计数器位数

16 位

时钟源

PCLK(外设时钟)

输出模式

Edge Aligned(边沿对齐)

支持分频

1/2/4/8/16/32/64/128

频率范围

12Hz-100MHz(@PCLK=100MHz)

占空比精度

1%(1%-99%)

适用场景

电机控制、LED调光、信号生成

说明

  • 当前驱动使用 PCLK 时钟源和 Edge Aligned 模式

  • HAL 层还支持 XTAL/EXT 时钟源和 Central Aligned 模式(当前未使用)

频率配置说明

时钟分频与频率范围

PWM 驱动使用 PCLK(外设时钟)作为基准时钟,支持 8 种分频配置。

分频配置表(PCLK = 100 MHz):

时钟分频

分频系数

有效时钟

最小频率

最大频率

÷1

2^0

100 MHz

1526 Hz

100 MHz

÷2

2^1

50 MHz

763 Hz

50 MHz

÷4

2^2

25 MHz

382 Hz

25 MHz

÷8

2^3

12.5 MHz

191 Hz

12.5 MHz

÷16

2^4

6.25 MHz

95 Hz

6.25 MHz

÷32

2^5

3.125 MHz

48 Hz

3.125 MHz

÷64

2^6

1.5625 MHz

24 Hz

1.5625 MHz

÷128

2^7

781.25 kHz

12 Hz

781.25 kHz

计算公式:

有效时钟 = PCLK ÷ 2^shift
最小频率 = 有效时钟 / 65535
最大频率 = 有效时钟 / 1

频率选择策略

驱动采用智能时钟分频选择机制:

  1. 第一次调用 lisa_pwm_set()

    • 自动选择能够支持目标频率的最优时钟分频

    • 配置 HAL 层时钟分频

  2. 后续调用 lisa_pwm_set()

    • 优先检查当前时钟分频是否支持新频率

    • 如果支持,直接调整频率和占空比(无需重新配置)

    • 如果不支持,返回错误并提示

示例(PCLK=100MHz):

// 第一次设置 1kHz,驱动选择 shift=1 (50MHz, 支持 763Hz-50MHz)
lisa_pwm_set(pwm, 0, 1000, 10);    // ✓ 返回 0

// 后续在 763Hz-50MHz 范围内可以随意调整
lisa_pwm_set(pwm, 0, 2000, 30);    // ✓ 返回 0
lisa_pwm_set(pwm, 0, 10000, 90);   // ✓ 返回 0
lisa_pwm_set(pwm, 0, 800, 50);     // ✓ 返回 0

// 超出当前分频范围会失败
lisa_pwm_set(pwm, 0, 123, 50);     // ✗ 返回 -1 (需要 shift=4)

极性配置

PWM 支持两种输出极性:

  • LISA_PWM_POLARITY_NORMAL - 正常极性

    • 高电平有效

    • 占空比表示高电平时间比例

    • 适用于大多数应用场景

  • LISA_PWM_POLARITY_INVERTED - 反转极性

    • 低电平有效

    • 占空比表示低电平时间比例

    • 适用于需要低电平驱动的设备

参数范围

参数

范围

说明

频率

12 Hz – 100 MHz

实际范围取决于 PCLK(100MHz 时约 12Hz-100MHz)

占空比

1% – 99%

精度 1%,硬件不支持 0% 或 100%

通道数

0 – 7

8 个独立通道

注意事项

  1. 引脚配置: 使用 PWM 通道前必须通过板型 pinmux 配置将对应引脚切换为 PWM 功能

  2. 推荐使用顺序: lisa_pwm_set()lisa_pwm_enable() → 动态调整 lisa_pwm_set()lisa_pwm_disable()

  3. 占空比限制: 硬件仅支持 1%-99% 占空比,不支持 0% 或 100%(HAL 层强制要求)

  4. 时钟分频自动选择: 驱动会根据目标频率自动选择最佳时钟分频,无需手动配置

  5. 连续调用支持: 可在同一时钟分频范围内连续多次调用 lisa_pwm_set() 修改频率和占空比

  6. 频率范围约束: 第一次调用确定时钟分频后,后续调用的频率必须在相同分频范围内

  7. 频率兼容性检查: 如果新频率需要不同的时钟分频,会返回 LISA_DEVICE_ERR_INVALID 并提示具体原因

  8. 极性配置建议: 极性修改建议在通道禁用状态下进行

  9. 通道独立性: 8 个通道完全独立,每个通道的时钟分频、频率、占空比互不影响

  10. 线程安全: 驱动内部使用互斥锁保护,支持多线程并发访问

  11. 时钟依赖: PWM 输出频率依赖于系统 PCLK 配置(典型值 24/48/100 MHz)

返回值说明

返回值

说明

LISA_DEVICE_OK (0)

成功

LISA_DEVICE_ERR_INVALID (-1)

参数无效(如占空比超出范围、频率需要不同时钟分频)

LISA_DEVICE_ERR_RANGE

通道号超出范围(有效范围 0-7)

LISA_DEVICE_ERR_NOT_READY

设备未初始化或通道未配置

LISA_DEVICE_ERR_IO (-10)

底层 HAL 操作失败

LISA_DEVICE_ERR_NOT_SUPPORT

操作不受支持

常见错误场景:

  1. 频率超出当前分频范围

    lisa_pwm_set(pwm, 0, 5000, 50);    // 返回 0,选择 shift=0 (1526Hz-100MHz)
    lisa_pwm_set(pwm, 0, 123, 50);     // 返回 -1,需要 shift=4 (95Hz-6.25MHz)
    // 错误提示:Frequency 123 Hz requires shift 4, current shift 0
    
  2. 占空比超出范围

    lisa_pwm_set(pwm, 0, 5000, 0);     // 返回 -1,硬件不支持 0%
    lisa_pwm_set(pwm, 0, 5000, 100);   // 返回 -1,硬件不支持 100%
    

建议

  • 在应用设计时选择在相同分频范围内的频率

  • 例如:1kHz-50kHz 都可以使用 shift=1(50MHz),可以随意切换

  • 避免跨越多个数量级的频率变化(如 50kHz ↔ 100Hz)

文件说明

  • lisa_pwm.h - 驱动头文件,包含所有 API 和类型定义

  • lisa_pwm_arcs.c - ARCS 平台适配实现

  • CMakeLists.txt - 构建配置

  • Kconfig - 配置选项