本人【Luckfox幸狐 RV1106 Linux 开发板测评】帖子链接:
一、开箱及测试
二、SDK获取与编译镜像
三、GPIO点灯
四、通过PC机共享网络接入Internet和Ubuntu下Python点灯
五、编译Buildroot系统并测试摄像头
测试了Luckfox Pro Max加摄像头和RKNN图像识别后,本人准备按测评计划先对板子的各种接口进行实验,本篇测评PWM,依然参考Luckfox Wiki之PWM篇:https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-PWM 。
1、PWM测评准备工作
先看板子的PWM管脚分布,手册说明系统默认开启的是PWM10,即GPIO1_C6_d管脚。
图6-1 Pro Max板IO分布
然后,如本人第三篇GPIO测评一样,通过面包板连接一个LED进行呼吸灯测试,管脚(板子5号脚)连接LED阴极,LED阳极串联1k电阻连接到3V3(板子36号脚)
本机Win10系统依然通过ADB登录开发板,利用echo命令来操作PWM。测试时,个人感觉手册写的测试命令执行顺序有点错乱,经过几次尝试总结命令如下:
// 查看PWM设备
# ls -l /sys/class/pwm
total 0
lrwxrwxrwx 1 root root 0 Jan 1 12:00 pwmchip10 -> ../../devices/platform/ff490020.pwm/pwm/pwmchip10
lrwxrwxrwx 1 root root 0 Jan 1 12:00 pwmchip11 -> ../../devices/platform/ff490030.pwm/pwm/pwmchip11
lrwxrwxrwx 1 root root 0 Jan 1 12:00 pwmchip5 -> ../../devices/platform/ff360010.pwm/pwm/pwmchip5
lrwxrwxrwx 1 root root 0 Jan 1 12:00 pwmchip6 -> ../../devices/platform/ff360020.pwm/pwm/pwmchip6
// 将PWM10_M1(GPIO1_C6_d)导出到用户空间
# echo 0 > /sys/class/pwm/pwmchip10/export
// 查看PWM10单个通道的属性文件(不做上一步导出到用户空间,这条命令会失败)
# ls /sys/class/pwm/pwmchip10/pwm0/
capture enable period power
duty_cycle output_type polarity uevent
// 使能PWM10通道,但是会提示参数错误
# echo 1 > /sys/class/pwm/pwmchip10/pwm0/enable
sh: write error: Invalid argument
// 但是如果先设置PWM周期——这里单位ns,1000000ns即1KHz频率
# echo 1000000 > /sys/class/pwm/pwmchip10/pwm0/period
// 然后再使能PWM10就成功了——必须先使能,不然没有PWM输出
# echo 1 > /sys/class/pwm/pwmchip10/pwm0/enable
// 此时输出最高值LED最亮(LED是低电平点亮),输出0 LED完全熄灭
# echo 1000000 > /sys/class/pwm/pwmchip10/pwm0/duty_cycle
# echo 0 > /sys/class/pwm/pwmchip10/pwm0/duty_cycle
// 设置PWM极性正常
# echo "normal" > /sys/class/pwm/pwmchip10/pwm0/polarity
// 结果发现输出0 LED最亮了,这说明PWM初始是inversed状态
# echo 0 > /sys/class/pwm/pwmchip10/pwm0/duty_cycle
// 设置PWM极性翻转
# echo "inversed" > /sys/class/pwm/pwmchip10/pwm0/polarity
// 果然又恢复输出最高值LED最亮
# echo 1000000 > /sys/class/pwm/pwmchip10/pwm0/duty_cycle
2、C程序控制PWM
依然使用文档提供的C代码,在虚拟机中建立pwm.c源文件,然后利用luckfox-pico SDK中提供的编译工具链进行编译,得到程序文件pwm。接着,就是拷贝到本机,再通过adb push到开发板自建的目录app下。最后就是开发板上给pwm执行权限,然后运行程序,即得到呼吸灯实验效果。
图6-2 开发板执行PWM程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// 定义PWM路径
#define PWM_PATH "/sys/class/pwm/pwmchip10"
// 定义周期(纳秒)
#define PERIOD_NS 1000000
// 定义最小占空比(纳秒)
#define MIN_DUTY_CYCLE_NS 0
// 定义最大占空比(纳秒)
#define MAX_DUTY_CYCLE_NS 1000000
int main() {
// 打开PWM的export文件,准备导出PWM通道
FILE *pwm_export = fopen(PWM_PATH "/export", "w");
if (!pwm_export) {
perror("Failed to open PWM export");
return 1;
}
fprintf(pwm_export, "0"); // 导出第一个PWM通道(索引为0)
fclose(pwm_export);
// 打开PWM通道的周期配置文件,设置周期为PERIOD_NS纳秒
FILE *period_file = fopen(PWM_PATH "/pwm0/period", "w");
if (!period_file) {
perror("Failed to open PWM period");
return 1;
}
fprintf(period_file, "%d", PERIOD_NS);
fclose(period_file);
// 打开PWM通道的使能文件,启用PWM通道
FILE *enable_file = fopen(PWM_PATH "/pwm0/enable", "w");
if (!enable_file) {
perror("Failed to open PWM enable");
return 1;
}
fprintf(enable_file, "1"); // 启用PWM通道
fclose(enable_file);
int direction = 1; // 方向,决定占空比是增加还是减少
int duty_cycle_ns = 0; // 当前占空比,初始值为0
while (1) { // 无限循环,使PWM保持持续输出
duty_cycle_ns += 10000 * direction; // 根据方向增加或减少占空比的值
if(duty_cycle_ns == MAX_DUTY_CYCLE_NS) // 如果达到最大占空比
direction = -1; // 改变方向,从增加变为减少
else if(duty_cycle_ns == MIN_DUTY_CYCLE_NS) // 如果达到最小占空比
direction = 1; // 改变方向,从减少变为增加
// 打开PWM通道的占空比配置文件,设置占空比为duty_cycle_ns纳秒
FILE *duty_cycle_file = fopen(PWM_PATH "/pwm0/duty_cycle", "w");
if (!duty_cycle_file) {
perror("Failed to open PWM duty cycle");
return 1;
}
fprintf(duty_cycle_file, "%d", duty_cycle_ns);
fclose(duty_cycle_file);
usleep(50000); // 暂停50000微秒(即0.05秒)再更新占空比,以实现PWM效果
}
// 最后,别忘了在程序结束前取消导出PWM通道,以释放资源
FILE *pwm_unexport = fopen(PWM_PATH "/unexport", "w");
if (!pwm_unexport) {
perror("Failed to open PWM unexport");
return 1;
}
fprintf(pwm_unexport, "0"); // 取消导出第一个PWM通道(索引为0)
fclose(pwm_unexport);
return 0; // 主函数返回0,表示程序正常结束
}