之前在uboot命令行验证一些小IP的寄存器,发现某款板子u-boot/cmd下面并没有pwm.c代码,补充一份。
#include <common.h>
#include <command.h>
#include <dm.h>
#include <pwm.h>
enum pwm_cmd {
PWM_SET_INVERT,
PWM_SET_CONFIG,
PWM_SET_ENABLE,
PWM_SET_DISABLE,
};
static int do_pwm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
const char *str_cmd, *str_channel = NULL, *str_enable = NULL;
const char *str_pwm = NULL, *str_period = NULL, *str_duty = NULL;
enum pwm_cmd sub_cmd;
struct udevice *dev;
u32 channel, pwm_enable, pwm_dev, period_ns = 0, duty_ns = 0;
int ret;
if (argc < 4) //参数个数argc < 4是因为在U_BOOT_CMD中所有命令最少的参数个数就是4个, 包括命令名本身, 例如pwm config 1 2 5000000 2500000 就是6个参数 。
show_usage:
return CMD_RET_USAGE;
str_cmd = argv[1];
argc -= 2;
argv += 2;
str_pwm = *argv;
argc--;
argv++;
//printf("str_pwm 0x%p\n", str_pwm);
if (!str_pwm) {
goto show_usage;
}
/* parse the behavior */
switch(*str_cmd) {
case 'i':
sub_cmd = PWM_SET_INVERT;
if (argc != 2)
goto show_usage;
break;
case 'c':
sub_cmd = PWM_SET_CONFIG;
if (argc != 3) //剩余参数个数
goto show_usage;
break;
case 'e':
sub_cmd = PWM_SET_ENABLE;
if (argc != 1)
goto show_usage;
break;
case 'd':
sub_cmd = PWM_SET_DISABLE;
if (argc != 1)
goto show_usage;
break;
default:
goto show_usage;
}
pwm_dev = simple_strtoul(str_pwm, NULL, 10);
ret = uclass_get_device(UCLASS_PWM, pwm_dev, &dev);
if (ret) {
printf("pwm '%s' not found\n", str_pwm);
return cmd_process_error(cmdtp, ret);
}
str_channel = *argv;
channel = simple_strtoul(str_channel, NULL, 10);
argc--;
argv++;
if (sub_cmd == PWM_SET_INVERT) {
str_enable = *argv;
pwm_enable = simple_strtoul(str_enable, NULL, 10);
ret = pwm_set_invert(dev, channel, pwm_enable);
} else if (sub_cmd == PWM_SET_CONFIG) {
str_period = *argv;
argc--;
argv++;
period_ns = simple_strtoul(str_period, NULL, 10);
str_duty = *argv;
duty_ns = simple_strtoul(str_duty, NULL, 10);
ret = pwm_set_config(dev, channel, period_ns, duty_ns);
} else if (sub_cmd == PWM_SET_ENABLE) {
ret = pwm_set_enable(dev, channel, 1);
} else if(sub_cmd == PWM_SET_DISABLE) {
ret = pwm_set_enable(dev, channel, 0);
}
if (ret) {
printf("error(%d)\n", ret);
return CMD_RET_FAILURE;
}
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(pwm, 6, 0, do_pwm, //参数6代表下所有输入的命令中最大参数为6个
"control pwm channels",
"pwm invert <pwm_dev_num> <channel> <polarity> - invert polarity\n"
"pwm config <pwm_dev_num> <channel> <period_ns> <duty_ns> - config PWM\n"
"pwm enable <pwm_dev_num> <channel> - enable PWM output\n"
"pwm disable <pwm_dev_num> <channel> - disable PWM output\n"
"Note: All input values are in decimal");
整套验证流程符合u-boot DM模型,即从u-boot/cmd/pwm.c调用到u-boot/drivers/pwm/下面的uclass的driver pwm-uclass.c,进而再通过pwm_ops结构体调用到u-boot/cmd/pwm/下面的udevice的driver xx_pwm.c去操作相关寄存器。也可以不用u-boot的这套DM模型,直接从u-boot/cmd/pwm.c调用到xx_pwm.c驱动。
在u-boot命令行敲ctrl+c进入命令行后如果发现没有pwm命令,则要在u-boot/configs/下面的xx_defconfig(xx一般是板子编号)文件中添加一个宏:CONFIG_CMD_PWM=y。再重新编译u-boot烧写进板子。
一共需要在xx_defconfig中添加三个宏:
1.CONFIG_CMD_PWM=y ,此宏对应cmd/pwm.c同路径的makefile,编译pwm.c文件
2.CONFIG_DM_PWM=y ,此宏对应pwm-uclass.c同路径的makefile,编译pwm-uclass.c文件
3.CONFIG_PWM_xx=y,此宏对应xx_pwm.c同路径的makefile,编译xx_pwm.c文件
如果某个板子默认进入uboot命令行的时间为0,宏CONFIG_BOOTDELAY=0一般定义在u-boot/configs的xx_defconfig中,可以将其改为CONFIG_BOOTDELAY=5,方便进入命令行。
在调试uboot命令行pwm命令的时候主要出现两个问题:
1、是在pwm.c的U_BOOT_CMD()中定义的嘴一个_help参数无法在串口打印出来,是因为在pwm.c中少加了一个头文件#include <common.h>
2、在rk3588_defconfig中定义了CONFIG_CMD_PWM=y,在u-boot/cmd/makefile中定义了obj-$(CONFIG_CMD_PWM) += pwm.o,但是这个宏CONFIG_CMD_PWM并没有起作用,即在u-boot/cmd/下面添加的pwm.c文件没有被编译到。所以还要在u-boot/cmd/Kconfig中定义PWM如下:
config CMD_PWM
bool “pwm”
default y
help
PWM support.
这样CONFIG_CMD_PWM才会起作用,当然也可以obj-y += pwm.o。
=> pwm config指令
pwm config 1 2 5000000 25000000