PWM使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 04/25/2024 |
1. 概述¶
PWM (Pulse Width Modulation) 模块用于产生脉宽波形,可通过改变频率和占空比来改变输出的电流、电压进而实现控制电机转速、液晶屏调光等功能;SigmaStar的PWM模块同时具备Group功能(细分为sync 、round、hold、stop),即每4个channel的PWM可绑定成一组,实现4路PWM同步产生或停止。
2. 功能描述¶
-
支持PWM的channel数量为11个,支持加入各自的Group
-
支持的OSCCLK(Hz)为:86M、12M、6M、3M、1.5M、1M、32K、8K
-
频率的工作范围是(OSCCLK/2)到(OSCCLK/2^34) ,例如OSCCLK = 12MHz,则范围是(0.0007Hz~6MHz);
-
支持double buffer来防止产生错误波形,即波形更新会等待当前波形完全生成之后;
-
支持sync功能,即Group内的PWM在同一个时刻产生波形,一般一组Group中会包含4个channel的PWM
-
支持round功能,即同Group内的PWM会在产生特定数量的脉冲后停止
-
支持hold功能,即同Group内的PWM会在完成当前周期的波形后暂停,常用于改变波形的设定,可设定暂停时间内的高低电平
-
支持stop功能,即同Group内的PWM会紧急停止
3. 相关概念说明¶
3.1. 频率和占空比¶
-
频率(frequency)
每秒钟信号从高电平到低电平再回到高电平的次数。
-
占空比(duty cycle)
高电平持续时间和低电平持续时间之间的比例。
-
举例说明
假设PWM的OSCCLK频率为12M,那么可设置的频率范围为:0.0007Hz~6MHz;
设定PWM0和PWM1为频率120Hz,占空比25%的波形,且PWM1相对于PWM0有180°的相位偏移,那么各参数配置如下:
period duty shift PWM0 120Hz 25% 0% PWM1 120Hz 75% 50% 产生的波形如下图:
3.2. 普通精度模式¶
kernel config中不开启CONFIG_SSTAR_PWM_EXTEND(Support high precision calculation)
,则使用普通精度模式,该模式下配置PWM的period的单位为Hz,duty cycle的单位为百分比。
假设要设置PWM0频率为10000HZ,占空比为50%,则:
period = 10000
duty cycle = 50
以sys/class/pwm/下的接口举例,配置方法如下:
# 跳转到PWM控制目录 cd sys/class/pwm/pwmchip0/ # 创建PWM0节点 echo 0 > export # 进入PWM0控制目录 cd pwm0 # 设置频率为10000Hz echo 10000 > preiod # 设置占空比为50% echo 50 > duty_cycle # 设置极性为反向(不设置反向为echo normal > polarity) echo inversed > polarity # 使能PWM0 echo 1 > enable
3.3. 高精度模式¶
kernel config中开启CONFIG_SSTAR_PWM_EXTEND(Support high precision calculation)
选项时,则使用高精度模式,该模式下配置PWM的period和duty_cycle均使用纳秒为单位,所以要先计算周期和占空比的值。
假设要设置PWM0频率为10000.5HZ,占空比为49.5%,则:
period = 10^9 ÷ 10000.5 = 99995
duty cycle = 99995 * 49.5% = 49498
以sys/class/pwm/下的接口举例,配置方法如下:
# 跳转到PWM控制路径 cd sys/class/pwm/pwmchip0/ # 创建PWM0节点 echo 0 > export # 进入PWM0控制路径 cd pwm0 # 设置频率为10000.5Hz echo 99995> period # 设置占空比为49.5% echo 49498> duty_cycle # 使能PWM0 echo 1 >enable
由此可见,高精度模式的优势在于参数设定支持到小数。
3.4. GROUP相关概念¶
3.4.1. Sync mode¶
sync mode可以将每个pwm channel加入到各自的Group群组中,完成同时对多个PWM进行控制的目的,一个Group有3~4个pwm channel,且Group与channlel对应关系如下:
Group | Group Member |
---|---|
Group0 | PWM0、PWM1、PWM2、PWM3 |
Group1 | PWM4、PWM5、PWM6、PWM7 |
Group2 | PWM8、PWM9、PWM10 |
可通过以下方式选择是否将pwm加入到Group中:
方式一:各channel DTS配置group属性
group属性决定了/sys/class/sstar/pwm下的各channel layout
以channel 0 举例,DTS配置group = <0>
,选择加入group0
channel 0的目录在/sys/class/sstar/pwm/group0/目录下:
以channel 1 举例,DTS不配置group属性,选择不加入group0各channel的目录
channel 1在/sys/class/sstar/pwm目录下:
方式二:/sys/class/sstar/group下使用join接口,echo [channel] [enable] > join
加入: echo 0 1 > join
退出: echo 0 0 > join
注意:方式一中DTS不配置group属性,就无法在方式二自由加入group
3.4.2. Hold mode¶
Group的Hold功能会在pwm完成当前周期的波形后停止,并触发中断,此时可以改变各channel波形的配置以保持同步,完成修改后会关闭hold 功能,pwm就会重新产生新的波形,每组group都有自己独立的hold功能。
举例:高精度模式下,group0下的所有channel已经输出100HZ,50%占空比,极性normal的波形,在此基础上将周期修改成1000HZ。
#跳转到group路径 cd sys/class/sstar/pwm/group0 #设置group0下所有channal输出100HZ,50%占空比,极性normal的波形 echo 10000000 > g_period echo 7500000 > g_duty echo 2500000 > g_shift echo 0 > g_polarity echo 1 > update // 触发hold mode echo 1 > g_enable #将周期修改为1000HZ echo 1000000 > g_period ehco 1 > update // 触发hold mode
3.4.3. Round mode¶
round功能会在同group内的所有channel完成一定数量的脉冲后停止,每组group都有自己独立的round功能。
举例:group0下的所有channel已经输出1000HZ,50%占空比,极性normal的波形,在此基础上分别触发100,200,300个脉冲后停止。
#跳转到group路径 cd sys/class/sstar/pwm/group0 #设置group0下所以channal输出1000HZ,50%占空比,极性normal的波形 echo 1000000 > g_period echo 750000 > g_duty echo 250000 > g_shift echo 0 > g_polarity echo 1 > update echo 1 > g_enable #触发100个脉冲 echo 100 > round #触发200个脉冲 echo 200 > round #触发300个脉冲 echo 300 > round
3.4.4. Stop mode¶
stop功能可以让当前group中的PWM立即停止(不会等当前周期完成)并维持结束时的电平,每组group都有自己独立的stop功能。
举例:使用stop暂停一段时间后再恢复波形
#跳转到group路径 cd sys/class/sstar/pwm/group0 #设置group0下所以channel输出1000HZ,50%占空比,极性normal的波形 echo 1000000 > g_period echo 750000 > g_duty echo 250000 > g_shift echo 0 > g_polarity echo 1 > update echo 1 > g_enable #急停波形 echo 1 > stop #恢复波形 echo 0 > stop
注意:stop 时间不建议太长,尤其是pwm停止后维持的电平为高电平时。
4.PADMUX配置¶
PWM在Uboot及Kernel环境下的padmux配置方法一致,只需要根据选择的引脚在对应的padmux.dtsi中加入如下所示的代码:
<PAD_PWM0 PINMUX_FOR_PWM0_MODE_1 MDRV_PUSE_PWM0 >; <PAD_PWM1 PINMUX_FOR_PWM1_MODE_1 MDRV_PUSE_PWM1 >; <PAD_GPIO2 PINMUX_FOR_PWM2_MODE_4 MDRV_PUSE_PWM2 >; <PAD_GPIO3 PINMUX_FOR_PWM3_MODE_4 MDRV_PUSE_PWM3 >; <PAD_GPIO4 PINMUX_FOR_PWM4_MODE_3 MDRV_PUSE_PWM4 >; <PAD_GPIO5 PINMUX_FOR_PWM5_MODE_3 MDRV_PUSE_PWM5 >; <PAD_GPIO6 PINMUX_FOR_PWM6_MODE_3 MDRV_PUSE_PWM6 >; <PAD_GPIO7 PINMUX_FOR_PWM7_MODE_3 MDRV_PUSE_PWM7 >; <PAD_GPIO0 PINMUX_FOR_PWM8_MODE_1 MDRV_PUSE_PWM8 >; <PAD_GPIO14 PINMUX_FOR_PWM9_MODE_3 MDRV_PUSE_PWM9 >; <PAD_GPIO15 PINMUX_FOR_PWM10_MODE_3 MDRV_PUSE_PWM10>;
第一列为引脚索引号,可以在drivers/sstar/inlcude/{chipname}/gpio.h
中查到;
第二列为模式定义,在drivers/sstar/gpio/{chipname}/hal_pinmux.c
中hal_gpio_st_padmux_info
数组里,罗列了所有引脚的复用关系,查询该引脚支持哪些复用功能可以查询该数组;
第三列为引脚及搭配模式的索引名称,可在drivers/sstar/include/drv_puse.h
里查询。
5. Uboot用法介绍¶
5.1. Uboot Config配置¶
在编译Uboot时需要选择的配置如下:
SigmaStar drivers-> <*> SigmaStar PWM-> <*> Support high precision calculation // 切换普通精度与高精度模式
5.2. 配置DTS¶
PWM的DTS配置只需要在对应的chipname.dtsi中配置如下信息(可以根据需求选择性配置PWM channel的数量,最多可以同时配置11个channel):
pwm0: pwm@0x1F203200{ compatible = "sstar,pwm"; reg = <0x1F203200 0x37>; channel = <0>; clock-freq = <12000000>; status = "okay"; };
PWM DTS配置说明:
属性 | 描述 | 设定值 | 备注 |
---|---|---|---|
compatible | 匹配驱动进行驱动注册 | "sstar,pwm" | 禁止修改 |
reg | 设定寄存器bank地址 | / | 禁止修改 |
channel | 匹配channel index | 0~10 | 不需要更改 |
clock-freq | 设定OSCCLK | 详见支持的OSCCLK | 可根据需要修改 |
status | 选择是否使能PWM驱动 | "ok" or "disable" | 可根据需要修改 |
5.3. Uboot cmd参数说明¶
-
配置PWM 频率及占空比:
pwm config <pwm_dev_num> <channel> <period_ns> <duty_ns> - config PWM pwm_dev_num: 输入0~13选择想要配置的channel channel: 输入0~13选择想要配置的channel period_ns: 输入频率 duty_ns: 输入占空
-
配置PWM极性:
pwm invert <pwm_dev_num> <channel> <polarity> - invert polarity pwm_dev_num: 输入0~13选择想要配置的channel channel: 输入0~13选择想要配置的channel polarity: 输入0表示极性正常,输入1表示极性相反
-
enbale PWM:
pwm enable <pwm_dev_num> <channel> - enable PWM output pwm_dev_num: 输入0~13选择想要配置的channel channel: 输入0~13选择想要配置的channel
-
disable PWM:
pwm disable <pwm_dev_num> <channel> - eisable PWM output pwm_dev_num: 输入0~13选择想要配置的channel channel: 输入0~13选择想要配置的channel
5.4. Uboot cmd使用实例截图¶
6. Kernel用法介绍¶
6.1. Kernel Config配置¶
在编译kernel时需要选择的配置如下:
Device Drivers--> [*] SStar SoC platform drivers--> [*] Sigmastar PWM driver [*] Support high precision calculation // 切换普通精度与高精度模式
6.2. 配置DTS¶
PWM的dts配置只需要在对应的chipname.dtsi中配置如下信息(可以根据需求选择性配置PWM channel的数量,最多可以同时配置11个channel):
pwm0: pwm@0x1F003400{ compatible = "sstar,pwm"; reg = <0x1F003400 0x37>; #pwm-cells = <3>; channel = <0>; group = <0>; clocks = <&CLK_pm_pwm>; clk-select = <0>; interrupts=<GIC_SPI INT_IRQ_PWM_INT_ALL IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; ....... pwm9: pwm@0x1F003880 { compatible = "sstar,pwm"; reg = <0x1F003880 0x37>; #pwm-cells = <3>; channel = <9>; group = <2>; clocks = <&CLK_pm_pwm>; clk-select = <0>; interrupts=<GIC_SPI INT_IRQ_PWM_INT_ALL IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; pwm10: pwm@0x1F003900 { compatible = "sstar,pwm"; reg = <0x1F003900 0x37>; #pwm-cells = <3>; channel = <10>; group = <2>; clocks = <&CLK_pm_pwm>; clk-select = <0>; interrupts=<GIC_SPI INT_IRQ_PWM_INT_ALL IRQ_TYPE_LEVEL_HIGH>; status = "ok"; };
PWM DTS配置说明:
属性 | 描述 | 设定值 | 备注 |
---|---|---|---|
compatible | 匹配驱动进行驱动注册,需与代码中一致 | "sstar,pwm" | 禁止修改 |
reg | 设定寄存器bank的地址 | / | 禁止修改 |
interrupts | 指定使用的硬件中断号及属性 | INT_IRQ_PWM_GROUPX | 禁止修改 |
clocks | 指定使用的时钟源 | CLK_pm_pwm | 禁止修改 |
channel | 匹配channel index | 0~10 | 禁止修改 |
group | 指定是否加入group | 不配置该属性则不加入group,加入group配置0/½/3,详见Group与channlel对应关系 | 可根据需要修改 |
clk-select | 用于选择时钟档位 | pwm010可选07分别对应12M/32K/1.5M/1M/8K/86M/6M/3M; | pwm0~10选择必须一致 |
status | 选择是否使能PWM驱动 | "ok" or "disable" | 可根据需要修改 |
6.3. 模块使用介绍¶
6.3.1. sys/class/pwm¶
DTS配置N个pwm channel节点,sys/class/pwm目录下对应生成N个pwmchip0,在pwmchip0目录下执行echo 0 > export
,即可生成对应的pwm0目录,(由于每个pwmchip0下的npwm数值均为1,因此export的传参参数只能是0),之后可在pwm0目录下配置pwm相关属性:period、duty_cycle、polarity、enable,详见3.2. 普通精度模式或者3.3. 高精度模式
6.3.2. sys/class/sstar/pwm¶
sys/class/sstar/pwm目录结构如下:
-
一级目录
group0/½ → 对同group内的所有channel同步操作
pwm1 → 对未加入group内的channel单独操作
-
二级目录
group0 → 对同group内的所有channel同时设定period/shift/duty/polarity/enable,并触发hold/stop/round功能
-
三级目录
pwm1 → 对同group内的某一个channel进行操作,可单独设定period/shift/duty/polarity/enable
sys/class/sstar/pwm接口,在二级目录group下可针对所有属于group的channel进行统一设置,也可在该目录下独立设置各channel的属性;在三级目录下可独立设置各channel的属性,二级目录与三级目录设置channel的属性区别在于:二级目录下独立设置channel的属性后,需要echo 1 > update触发hold功能去更新参数,三级目录下独立设置channel的属性后,会立即生效
举例:group0下的所有channel同步且输出100HZ,50%占空比,极性normal的波形,然后将channel0的period修改为200HZ
#跳转到group路径 cd sys/class/sstar/pwm/group0 #设置group0下所以channal输出100HZ,50%占空比,极性normal的波形 echo 10000000 > g_period //group内所有channel的period都设为100HZ echo 7500000 > g_duty echo 2500000 > g_shift //占空比为(7500000-2500000)/ 10000000 = 50% echo 0 > g_polarity echo 1 > update //触发hold mode echo 1 > g_enable #修改channel0的period为200HZ,方法一: echo 0 20000000 > g_period //group内只设定channel 0的period为100HZ echo 1 > update //触发hold更新波形,仍然同步 #修改channel0的period为200HZ,方法二: cd /sys/class/sstar/pwm/group0/pwm0 echo 20000000 > period
6.3.3. ioctl¶
头文件<drv_pwm.h>
位于/driver/sstar/pwm目录下,struct pwm_ch_cfg结构体是对channel属性的描述,struct pwm_gp_cfg结构体是对group属性的描述
-
IOCTL_PWM_SET_CHAN_CFG:完成channel的参数配置
-
IOCTL_PWM_GET_CHAN_CFG:获取当前channel的参数配置
-
IOCTL_PWM_SET_GROUP_CFG:完成group的参数配置
-
IOCTL_PWM_GET_GROUP_CFG:获取当前group的参数配置
-
IOCTL_PWM_GROUP_STOP:触发stop功能
-
IOCTL_PWM_GROUP_ROUND:触发round功能
#ifndef __DRV_PWM_H__ #define __DRV_PWM_H__ #include <cam_os_wrapper.h> struct pwm_ch_cfg { u64 duty; //设定占空比,实际占空比=duty-shift u64 shift; //设定起始相位 u64 period; //设定周期 u8 enable; //波形使能 u32 channel; //指定channel u32 polarity; //极性设置:0-正常,1-极性取反 #ifdef CONFIG_SSTAR_PWM_DDT //ifado不支持 u64 p_ddt; //正向波形的死区时间,以ns为单位 u64 n_ddt; //反向波形的死区时间,以ns为单位 u8 ddt_en; //死区时间使能 #endif }; struct pwm_gp_cfg { u64 duty; u64 shift; u32 group; u64 period; u8 enable; u8 stop_en; //stop功能使能 u32 polarity; u32 round_num; //设定round mode下的脉冲数量 }; #define PWM_IOC_MAXNR 6 #define IOCTL_PWM_SET_CHAN_CFG_NR (0) #define IOCTL_PWM_GET_CHAN_CFG_NR (2) #define IOCTL_PWM_SET_GROUP_CFG_NR (1) #define IOCTL_PWM_GET_GROUP_CFG_NR (3) #define IOCTL_PWM_GROUP_STOP_NR (4) #define IOCTL_PWM_GROUP_ROUND_NR (5) #define PWM_IOC_MAGIC 'p' #define IOCTL_PWM_SET_CHAN_CFG _IO(PWM_IOC_MAGIC, IOCTL_PWM_SET_CHAN_CFG_NR) #define IOCTL_PWM_GET_CHAN_CFG _IO(PWM_IOC_MAGIC, IOCTL_PWM_GET_CHAN_CFG_NR) #define IOCTL_PWM_SET_GROUP_CFG _IO(PWM_IOC_MAGIC, IOCTL_PWM_SET_GROUP_CFG_NR) #define IOCTL_PWM_GET_GROUP_CFG _IO(PWM_IOC_MAGIC, IOCTL_PWM_GET_GROUP_CFG_NR) #define IOCTL_PWM_GROUP_STOP _IO(PWM_IOC_MAGIC, IOCTL_PWM_GROUP_STOP_NR) #define IOCTL_PWM_GROUP_ROUND _IO(PWM_IOC_MAGIC, IOCTL_PWM_GROUP_ROUND_NR) ...... #endif
Sample code:
#include <autoconf.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <drv_pwm.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/ioctl.h> int main(int argc, char **argv) { int ret = 0; int pwm_fd = -1; char path_name[24]; struct pwm_ch_cfg pwm_channel; struct pwm_gp_cfg pwm_group; if (argc != 4) { printf("format: ut_pwm <channel> [channel_id] [enable]\n"); printf("format: ut_pwm <group> [group_id] [enable]\n"); printf("format: ut_pwm <stop> [group_id] [enable]\n"); printf("format: ut_pwm <round> [group_id] [round_num]\n"); printf("format: ut_pwm <ddt> [channel_id] [dead_time]\n"); return -1; } if (!strcmp(argv[1], "channel")) { pwm_channel.period = 1000000; pwm_channel.duty = 500000; pwm_channel.shift = 200000; pwm_channel.polarity = 1; pwm_channel.channel = atoi(argv[2]); pwm_channel.enable = atoi(argv[3]); snprintf(path_name, sizeof(path_name), "/dev/pwm%u", pwm_channel.channel); pwm_fd = open((const char *)(char *)path_name, O_RDWR); if (pwm_fd < 0) { printf("open /dev/pwm%u fail errno:[%d]\n", pwm_channel.channel, pwm_fd); return -1; } ret = ioctl(pwm_fd, IOCTL_PWM_SET_CHAN_CFG, &pwm_channel); if (ret < 0) { printf("pwm channel[%u] set config fail\n", pwm_channel.channel); return ret; } ret = ioctl(pwm_fd, IOCTL_PWM_GET_CHAN_CFG, &pwm_channel); if (ret < 0) { printf("pwm channel[%u] get config fail\n", pwm_channel.channel); return ret; } usleep(500000); pwm_channel.duty = 700000; ret = ioctl(pwm_fd, IOCTL_PWM_SET_CHAN_CFG, &pwm_channel); if (ret < 0) { printf("pwm channel[%u] set config again fail\n", pwm_channel.channel); return ret; } } else if (!strcmp(argv[1], "group")) { pwm_group.period = 1000000; pwm_group.duty = 500000; pwm_group.shift = 200000; pwm_group.polarity = 0; pwm_group.group = atoi(argv[2]); pwm_group.enable = atoi(argv[3]); snprintf(path_name, sizeof(path_name), "/dev/pwm_group%u", pwm_group.group); pwm_fd = open((const char *)(char *)path_name, O_RDWR); if (pwm_fd < 0) { printf("open /dev/pwm-group%u fail errno:[%d]\n", pwm_group.group, pwm_fd); return -1; } ret = ioctl(pwm_fd, IOCTL_PWM_SET_GROUP_CFG, &pwm_group); if (ret < 0) { printf("pwm group[%u] set config fail\n", pwm_group.group); return ret; } ret = ioctl(pwm_fd, IOCTL_PWM_GET_GROUP_CFG, &pwm_group); if (ret < 0) { printf("pwm group[%u] get config fail\n", pwm_group.group); return ret; } pwm_group.duty = 800000; usleep(500000); ret = ioctl(pwm_fd, IOCTL_PWM_SET_GROUP_CFG, &pwm_group); if (ret < 0) { printf("pwm group[%u] set config again fail\n", pwm_group.group); return ret; } } else if (!strcmp(argv[1], "stop")) { pwm_group.group = atoi(argv[2]); snprintf(path_name, sizeof(path_name), "/dev/pwm_group%u", pwm_group.group); pwm_fd = open((const char *)(char *)path_name, O_RDWR); if (pwm_fd < 0) { printf("open /dev/pwm-group%u fail errno:[%d]\n", pwm_group.group, pwm_fd); return -1; } pwm_group.stop_en = atoi(argv[3]); ret = ioctl(pwm_fd, IOCTL_PWM_GROUP_STOP, &pwm_group); if (ret < 0) { printf("pwm group[%u] stop config fail\n", pwm_group.group); return ret; } } else if (!strcmp(argv[1], "round")) { pwm_group.group = atoi(argv[2]); snprintf(path_name, sizeof(path_name), "/dev/pwm_group%u", pwm_group.group); pwm_fd = open((const char *)(char *)path_name, O_RDWR); if (pwm_fd < 0) { printf("open /dev/pwm-group%u fail errno:[%d]\n", pwm_group.group, pwm_fd); return -1; } pwm_group.round_num = atoi(argv[3]); ret = ioctl(pwm_fd, IOCTL_PWM_GROUP_ROUND, &pwm_group); if (ret < 0) { printf("pwm group[%u] round config fail\n", pwm_group.group); return ret; } } #ifdef CONFIG_SSTAR_PWM_DDT else if (!strcmp(argv[1], "ddt")) { pwm_channel.channel = atoi(argv[2]); snprintf(path_name, sizeof(path_name), "/dev/pwm%u", pwm_channel.channel); pwm_fd = open((const char *)(char *)path_name, O_RDWR); if (pwm_fd < 0) { printf("open /dev/pwm%u fail errno:[%d]\n", pwm_channel.channel, pwm_fd); return -1; } ret = ioctl(pwm_fd, IOCTL_PWM_GET_CHAN_CFG, &pwm_channel); if (ret < 0) { printf("pwm channel[%u] get config fail\n", pwm_channel.channel); return ret; } pwm_channel.p_ddt = atoi(argv[3]); pwm_channel.n_ddt = atoi(argv[3]); pwm_channel.ddt_en = 1; ret = ioctl(pwm_fd, IOCTL_PWM_SET_CHAN_CFG, &pwm_channel); if (ret < 0) { printf("pwm channel[%u] set ddt config fail\n", pwm_channel.channel); return ret; } } #endif else { printf("erro pwm command\n"); } close(pwm_fd); return 0; }
6.4 Debug方法¶
6.4.1 PWM各接口不存在¶
-
检查DTS PWM节点的
status
是否为ok
-
检查kernel config是否配置,详见6.1. Kernel Config配置
6.4.2 配置后PWM无波形产生¶
Step1: 首先确认测量的引脚是否正确:打开对应的原理图确认即可,如果没有错误的话,则进行下一步。
Step2: 确认对应的PWM mode是否生效,引脚复用失败主要有两个原因:
原因一:该引脚没有设置为PWM mode,设置方法详见4.PADMUX配置
原因二:有优先级比PWM mode更高级别的padmux mode被开启,可以在编译的时候打开padmux回读机制的CONFIG:CONFIG_MSYS_PADMUX,它的功能是用于确认使用到的padmux是否有被成功设定,开启后在在user space输入如下命令查看:
echo PAD_PWM0 PINMUX_FOR_PWM0_MODE_1 > /sys/class/sstar/msys/mux_verify cat /sys/class/sstar/msys/mux_verify
可以从log的提示得知:若要将PAD_PWM0设为PWM0_MODE_1,需要将Bank:0x103C,Offset:0x68的bit[10:8]写0;将Bank:0x103C,Offset:0x6D的bit[6:4]写1。
Step3:检查相关参数是否设置成功
以pwm group0为例,输入如下命令查看参数:
cd /sys/class/sstar/pwm/group0/ cat g_info
如下图所示,channel 0 和channel 1频率和占空比设置成功,channel 0 enable是在正常输出波形,channel 1 disable,无波形产生,而channel 2 和 channel 3没有配置频率和占空比。