跳转到正文
知识笔记
通用

Linux LED 子系统的 sysfs 控制接口 ​

接口与驱动关系 ​

LED 驱动将设备注册到 /sys/class/leds/<led-name>/,用户空间通过属性文件控制逻辑亮度与触发器。底层 GPIO 或 PWM 的极性转换由驱动处理。

text
应用程序 → sysfs 属性 → LED 子系统 → LED 驱动 → GPIO / PWM

设备与属性 ​

bash
ls /sys/class/leds/
ls /sys/class/leds/sys-led/

sys-led 是示例名称,后续命令需替换为实际 LED 节点。

属性用途
brightness当前逻辑亮度,0 表示熄灭
max_brightness驱动支持的最大亮度值
trigger支持的触发器,方括号表示当前选中项
delay_on / delay_offtimer 触发器的亮、灭时长,单位为毫秒

brightness 与 GPIO 极性 ​

先读取 max_brightness。普通 GPIO LED 常为 1,支持多级亮度的设备可能为 255 或其他值,写入范围应按实际属性确认。

bash
cat /sys/class/leds/sys-led/max_brightness
cat /sys/class/leds/sys-led/brightness
echo none > /sys/class/leds/sys-led/trigger
echo 1 > /sys/class/leds/sys-led/brightness
echo 0 > /sys/class/leds/sys-led/brightness

brightness 表示 LED 的逻辑亮度,不是 GPIO 电平。即使设备树使用 GPIO_ACTIVE_LOW,用户空间通常仍以 0 表示熄灭、非零表示相应亮度;驱动负责将逻辑状态转换为实际电平。

trigger、timer 与 heartbeat ​

查询与手动控制bash
cat /sys/class/leds/sys-led/trigger
echo none > /sys/class/leds/sys-led/trigger
timer 闪烁,500 ms 亮、500 ms 灭bash
echo timer > /sys/class/leds/sys-led/trigger
echo 500 > /sys/class/leds/sys-led/delay_on
echo 500 > /sys/class/leds/sys-led/delay_off
heartbeat 触发器bash
echo heartbeat > /sys/class/leds/sys-led/trigger

触发器支持情况取决于内核配置和驱动。timer 对应属性通常在启用该触发器后出现;若没有 delay_on,先核对 trigger 中是否支持 timer。

C 语言控制示例 ​

以下保留通过 open/write/close 操作属性文件的示例。代码中的 rgb-led-r 与上文 sys-led 都是示例节点,移植时按实际设备修改宏定义。调用前确认触发器与亮度范围。

led_control.cc
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* 将 sysfs 路径提取为宏定义,方便针对不同硬件平台进行配置和移植 */
#define LED_TRIGGER_PATH    "/sys/class/leds/rgb-led-r/trigger"
#define LED_BRIGHTNESS_PATH "/sys/class/leds/rgb-led-r/brightness"

/* 统一的底层文件写入辅助函数 */
static int write_file(const char *path, const char *val)
{
    int fd = open(path, O_WRONLY);
    if (fd < 0) {
        fprintf(stderr, "Error opening %s: %s\n", path, strerror(errno));
        return -1;
    }

    /* 写入时带上 '\0' 结束符,避免内核读取到脏数据 */
    ssize_t ret = write(fd, val, strlen(val) + 1);
    if (ret < 0) {
        fprintf(stderr, "Error writing to %s: %s\n", path, strerror(errno));
        close(fd);
        return -1;
    }

    close(fd);
    return 0;
}

/* 打印使用帮助信息 */
static void print_usage(const char *prog)
{
    fprintf(stderr, 
        "Usage: %s [command] [args]\n\n"
        "Commands:\n"
        "  on                  Turn on the LED manually\n"
        "  off                 Turn off the LED manually\n"
        "  trigger <type>      Set LED trigger mode\n"
        "                      Supported types: none, heartbeat, timer, mmc0\n",
        prog
    );
}

int main(int argc, char *argv[])
{
    if (argc < 2) {
        print_usage(argv[0]);
        return EXIT_FAILURE;
    }

    if (strcmp(argv[1], "on") == 0) {
        /* 先切回手动模式,再设置亮度,并增加错误判断 */
        if (write_file(LED_TRIGGER_PATH, "none") < 0) return EXIT_FAILURE;
        if (write_file(LED_BRIGHTNESS_PATH, "1") < 0) return EXIT_FAILURE;

    } else if (strcmp(argv[1], "off") == 0) {
        if (write_file(LED_TRIGGER_PATH, "none") < 0) return EXIT_FAILURE;
        if (write_file(LED_BRIGHTNESS_PATH, "0") < 0) return EXIT_FAILURE;

    } else if (strcmp(argv[1], "trigger") == 0) {
        if (argc < 3) {
            fprintf(stderr, "Error: 'trigger' command requires a type argument.\n");
            print_usage(argv[0]);
            return EXIT_FAILURE;
        }
        /* 设置触发类型(如 heartbeat, timer, mmc0 等) */
        if (write_file(LED_TRIGGER_PATH, argv[2]) < 0) return EXIT_FAILURE;

    } else {
        fprintf(stderr, "Error: Unknown command '%s'\n", argv[1]);
        print_usage(argv[0]);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

权限与排查 ​

sudo echo 1 > brightness 中的重定向仍由当前 Shell 执行,可能出现 Permission denied。可用以下方式将写操作放在授权上下文中:

bash
echo 1 | sudo tee /sys/class/leds/sys-led/brightness
sudo sh -c 'echo 1 > /sys/class/leds/sys-led/brightness'
现象检查项
写入无效果实际 LED 节点、当前 trigger、亮度范围、GPIO 极性、pinctrl 与接线
缺少 delay_ontimer 是否受支持、是否已被选中
权限不足当前用户权限、节点权限与重定向执行用户
低电平有效时逻辑相反核对驱动与设备树极性,不将 brightness 直接当作物理电平

验证范围 ​

本文整理 LED sysfs 控制接口。不同设备、驱动与内核配置下的节点和触发器可能不同,实测应记录平台、内核版本、属性输出和 LED 现象。

参考资料 ​