PWM 应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

PWM 应用编程

在这里插入图片描述

应用层如何操控 PWM

PWM 控制方式

  • 通过 sysfs 进行操作,目录为 /sys/class/pwm

    • /sys/class/pwm 目录下的内容
  • 包含 8 个 pwmchipX 文件夹,对应 I.MX6U 的 8 个 PWM 控制器

    • pwmchip0 目录下的内容

PWM 控制器属性文件

  • npwm:只读,显示该 PWM 控制器下的 PWM 输出路数,I.MX6U 每个控制器只有 1 路 PWM 输出

    • 读取 npwm 属性文件
  • export:导出 PWM 控制器,命令示例:echo 0 > export

    • 导出 PWM
  • unexport:删除导出的 PWM 控制器,命令示例:echo 0 > unexport

PWM 控制过程

  • 导出后会生成 pwm0 目录,包含以下属性文件

    • pwm0 目录下的内容
  • enable:控制 PWM 的使能状态,写入 “0” 禁用,写入 “1” 使能

  • polarity:设置 PWM 极性,“normal” 为普通,“inversed” 为反转

    • 很多 SoC 的 PWM 外设其硬件上并不支持极性配置,所以对应的驱动程序中并未实现这个接口
  • period:配置 PWM 周期,单位为纳秒,例如:echo 10000 > period 设置周期为 10 微秒

  • duty_cycle:配置 PWM 占空比,单位为纳秒,例如:echo 5000 > duty_cycle 设置占空比为 5 微秒

注意事项

  • I.MX6U 的 PWM1 已用于 LCD 背光控制,应用层不能直接控制,其他 PWM 因 I/O 资源限制无法使用

编写应用程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

static char pwm_path[100];  // 静态字符数组,用于存储PWM设备路径

//配置PWM的属性
static int pwm_config(const char *attr, const char *val)
{
    char file_path[100];    // 字符数组,用于存储属性文件路径
    int len;    // 整数变量,用于存储属性值的长度
    int fd;

    sprintf(file_path, "%s/%s", pwm_path, attr);
    if (0 > (fd = open(file_path, O_WRONLY))) {
        perror("open error");
        return fd;
    }

    len = strlen(val);   // 获取属性值的长度
    if (len != write(fd, val, len)) {
        perror("write error");
        close(fd);
        return -1;
    }

    close(fd);  //关闭文件
    return 0;
}

int main(int argc, char *argv[])
{
    /* 校验传参 */
    if (4 != argc) {
        fprintf(stderr, "usage: %s <id> <period> <duty>\n",
                argv[0]);
        exit(-1);
    }

    /* 打印配置信息 */
    printf("PWM config: id<%s>, period<%s>, duty<%s>\n",
            argv[1], argv[2],
            argv[3]);

    /* 导出pwm */
    sprintf(pwm_path, "/sys/class/pwm/pwmchip%s/pwm0", argv[1]);

    //access 函数用于检查文件是否存在或是否具有某种访问权限
    //F_OK:检查文件是否存在
    if (access(pwm_path, F_OK)) {//如果pwm0目录不存在, 则导出

        char temp[100]; // 临时字符数组,用于存储导出路径
        int fd;

        sprintf(temp, "/sys/class/pwm/pwmchip%s/export", argv[1]);
        if (0 > (fd = open(temp, O_WRONLY))) {
            perror("open error");
            exit(-1);
        }

        if (1 != write(fd, "0", 1)) {//导出pwm
            perror("write error");
            close(fd);
            exit(-1);
        }

        close(fd);  //关闭文件
    }

    /* 配置PWM周期 */
    if (pwm_config("period", argv[2]))
        exit(-1);

    /* 配置占空比 */
    if (pwm_config("duty_cycle", argv[3]))
        exit(-1);

    /* 使能pwm */
    pwm_config("enable", "1");

    /* 退出程序 */
    exit(0);
}

校验传入的参数数量是否为4

  • 如果不是则打印使用说明并退出程序

打印PWM配置信息

  • 打印PWM的ID、周期和占空比信息

生成PWM设备路径,格式为 /sys/class/pwm/pwmchip{id}/pwm0

使用 access 函数检查PWM设备路径是否存在

  • 如果不存在,则生成导出路径并使用 open 和 write 函数导出PWM

调用 pwm_config 函数配置PWM的周期、占空比和使能状态

  • pwm_config 函数

    • 使用 sprintf 生成属性文件路径

    • 以只写模式打开属性文件,如果失败则打印错误信息并返回错误码

    • 获取属性值的长度,并将属性值写入文件。如果写入长度不匹配则打印错误信息并返回错误码

    • 关闭文件并返回成功码(0)

  • 如果失败则退出程序

退出程序

在开发板上测试

正点原子开发板出厂系统无法使用PWM,需要修改内核源码和设备树

修改设备树方法

  • 禁用LCD和backlight设备(设置status为disabled)

  • 重新编译设备树并替换开发板启动文件中的dtb文件

  • 参考《I.MX6U嵌入式Linux驱动开发指南》第七十三章内容自行配置PWM

简单方法

  • 不用重新编译设备树,直接在u-boot命令行模式下禁用LCD和backlight设备,腾出PWM1供测试

  • 步骤

    • 重启开发板,进入u-boot命令行模式

    • 修改内核设备树文件,将LCD和backlight设备的status属性改为“disabled”

      • SD/eMMC启动方式

        • setenv disable_lcd ‘fdt addr ${fdt_addr}; fdt set /backlight status disable; fdt set /soc/aips-bus@02100000/lcdif@021c8000 status disable’

          • 在u-boot环境中设置一个名为disable_lcd的环境变量,其值是一系列用于操作设备树(Device Tree)的命令

          • setenv disable_lcd

            • setenv 是u-boot中的一个命令,用于设置环境变量

            • disable_lcd 是这个环境变量的名称

          • 'fdt addr ${fdt_addr};

            • fdt 是u-boot中用于操作设备树的命令

            • addr 是fdt命令的一个子命令,用于设置设备树的地址

            • ${fdt_addr} 是一个环境变量,表示设备树(dtb文件)在内存中的地址

          • fdt set /backlight status disable;

            • set 是fdt命令的一个子命令,用于修改设备树中的属性

            • /backlight 是设备树中的一个节点路径,表示背光设备

            • status disable 是将/backlight节点的status属性设置为disable,表示禁用这个设备

          • fdt set /soc/aips-bus@02100000/lcdif@021c8000 status disable’

            • 这是另一个fdt set命令,用于修改设备树中的另一个节点

            • /soc/aips-bus@02100000/lcdif@021c8000 是设备树中的一个节点路径,表示LCD接口设备

            • status disable 是将/soc/aips-bus@02100000/lcdif@021c8000节点的status属性设置为disable,表示禁用这个设备

        • setenv mmcboot ‘echo Booting from mmc …; run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try;
          then if run loadfdt; then run disable_lcd; bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz;
          else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;’

      • NAND启动方式

        • setenv disable_lcd ‘fdt addr ${fdt_addr}; fdt set /backlight status disable; fdt set /soc/aips- bus@02100000/lcdif@021c8000 status disable’

        • setenv bootcmd ‘nand read ${loadaddr} 0x620000 0x800000;nand read ${fdt_addr} ${fdt_offset} 0x20000; run
          disable_lcd; bootz ${loadaddr} - ${fdt_addr}’

    • 执行两条命令后,执行boot命令启动开发板

  • 注意事项

    • 这种修改方式只对本次启动生效,重启后恢复原状态
  • 29
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不迷茫(˵¯͒¯͒˵)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值