Merged in paulpatience/nuttx-apps/pwm (pull request #16)

apps/examples/pwm: Add support for multiple output channels per timer
This commit is contained in:
Gregory Nutt 2015-11-01 16:54:10 -06:00
commit aaafb6fc6e
2 changed files with 272 additions and 21 deletions

View File

@ -17,27 +17,102 @@ config EXAMPLES_PWM_DEVPATH
string "PWM device path" string "PWM device path"
default "/dev/pwm0" default "/dev/pwm0"
---help--- ---help---
The path to the PWM device. Default: /dev/pwm0 The path to the PWM device. Default: /dev/pwm0
config EXAMPLES_PWM_FREQUENCY config EXAMPLES_PWM_FREQUENCY
int "Default PWM freququency" int "Default PWM frequency"
default 100 default 100
---help--- ---help---
The default PWM frequency. Default: 100 Hz The default PWM frequency. Default: 100 Hz
config EXAMPLES_PWM_DUTYPCT
int "Default PWM duty percentage"
default 50
---help---
The default PWM duty as a percentage. Default: 50%
config EXAMPLES_PWM_DURATION config EXAMPLES_PWM_DURATION
int "Default PWM duration" int "Default PWM duration"
default 5 default 5
---help--- ---help---
The default PWM pulse train duration in seconds. Used only if the current The default PWM pulse train duration in seconds. Used only if the current
pulse count is zero (pulse count is only supported if PWM_PULSECOUNT pulse count is zero (pulse count is only supported if PWM_PULSECOUNT
is not defined). Default: 5 seconds is not defined). Default: 5 seconds
if PWM_MULTICHAN
config EXAMPLES_PWM_DUTYPCT1
int "First PWM duty percentage"
default 50
range 1 99
---help---
The first PWM duty as a percentage. Default: 50%
config EXAMPLES_PWM_CHANNEL1
int "First PWM channel number"
default 1
range 1 4
---help---
The first PWM channel number. Default: 1
if PWM_NCHANNELS = 2 || PWM_NCHANNELS = 3 || PWM_NCHANNELS = 4
config EXAMPLES_PWM_DUTYPCT2
int "Second PWM duty percentage"
default 50
range 1 99
---help---
The second PWM duty as a percentage. Default: 50%
config EXAMPLES_PWM_CHANNEL2
int "Second PWM channel number"
default 2
range 1 4
---help---
The second PWM channel number. Default: 2
endif
if PWM_NCHANNELS = 3 || PWM_NCHANNELS = 4
config EXAMPLES_PWM_DUTYPCT3
int "Third PWM duty percentage"
default 50
range 1 99
---help---
The third PWM duty as a percentage. Default: 50%
config EXAMPLES_PWM_CHANNEL3
int "Third PWM channel number"
default 3
range 1 4
---help---
The third PWM channel number. Default: 3
endif
if PWM_NCHANNELS = 4
config EXAMPLES_PWM_DUTYPCT4
int "Fourth PWM duty percentage"
default 50
range 1 99
---help---
The fourth PWM duty as a percentage. Default: 50%
config EXAMPLES_PWM_CHANNEL4
int "Fourth PWM channel number"
default 4
range 1 4
---help---
The fourth PWM channel number. Default: 4
endif
endif
if !PWM_MULTICHAN
config EXAMPLES_PWM_DUTYPCT
int "Default PWM duty percentage"
default 50
range 1 99
---help---
The default PWM duty as a percentage. Default: 50%
config EXAMPLES_PWM_PULSECOUNT config EXAMPLES_PWM_PULSECOUNT
int "Default pulse count" int "Default pulse count"
@ -45,7 +120,9 @@ config EXAMPLES_PWM_PULSECOUNT
depends on PWM_PULSECOUNT depends on PWM_PULSECOUNT
---help--- ---help---
The initial PWM pulse count. This option is only available if The initial PWM pulse count. This option is only available if
PWM_PULSECOUNT is defined. Default: 0 (i.e., use the duration, not PWM_PULSECOUNT is defined. Default: 0 (i.e., use the duration, not
the count). the count).
endif endif
endif

View File

@ -59,6 +59,29 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* Configuration ************************************************************/
#ifdef CONFIG_PWM_MULTICHAN
# if CONFIG_PWM_NCHANNELS > 1
# if CONFIG_EXAMPLES_PWM_CHANNEL1 == CONFIG_EXAMPLES_PWM_CHANNEL2
# error "Channel numbers must be unique"
# endif
# endif
# if CONFIG_PWM_NCHANNELS > 2
# if CONFIG_EXAMPLES_PWM_CHANNEL1 == CONFIG_EXAMPLES_PWM_CHANNEL3 || \
CONFIG_EXAMPLES_PWM_CHANNEL2 == CONFIG_EXAMPLES_PWM_CHANNEL3
# error "Channel numbers must be unique"
# endif
# endif
# if CONFIG_PWM_NCHANNELS > 3
# if CONFIG_EXAMPLES_PWM_CHANNEL1 == CONFIG_EXAMPLES_PWM_CHANNEL4 || \
CONFIG_EXAMPLES_PWM_CHANNEL2 == CONFIG_EXAMPLES_PWM_CHANNEL4 || \
CONFIG_EXAMPLES_PWM_CHANNEL3 == CONFIG_EXAMPLES_PWM_CHANNEL4
# error "Channel numbers must be unique"
# endif
# endif
#endif
/**************************************************************************** /****************************************************************************
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
@ -67,7 +90,12 @@ struct pwm_state_s
{ {
bool initialized; bool initialized;
FAR char *devpath; FAR char *devpath;
#ifdef CONFIG_PWM_MULTICHAN
uint8_t channels[CONFIG_PWM_NCHANNELS];
uint8_t duties[CONFIG_PWM_NCHANNELS];
#else
uint8_t duty; uint8_t duty;
#endif
uint32_t freq; uint32_t freq;
#ifdef CONFIG_PWM_PULSECOUNT #ifdef CONFIG_PWM_PULSECOUNT
uint32_t count; uint32_t count;
@ -117,27 +145,82 @@ static void pwm_devpath(FAR struct pwm_state_s *pwm, FAR const char *devpath)
static void pwm_help(FAR struct pwm_state_s *pwm) static void pwm_help(FAR struct pwm_state_s *pwm)
{ {
#ifdef CONFIG_PWM_MULTICHAN
uint8_t channels[CONFIG_PWM_NCHANNELS] =
{
CONFIG_EXAMPLES_PWM_CHANNEL1,
#if CONFIG_PWM_NCHANNELS > 1
CONFIG_EXAMPLES_PWM_CHANNEL2,
#endif
#if CONFIG_PWM_NCHANNELS > 2
CONFIG_EXAMPLES_PWM_CHANNEL3,
#endif
#if CONFIG_PWM_NCHANNELS > 3
CONFIG_EXAMPLES_PWM_CHANNEL4,
#endif
};
uint8_t duties[CONFIG_PWM_NCHANNELS] =
{
CONFIG_EXAMPLES_PWM_DUTYPCT1,
#if CONFIG_PWM_NCHANNELS > 1
CONFIG_EXAMPLES_PWM_DUTYPCT2,
#endif
#if CONFIG_PWM_NCHANNELS > 2
CONFIG_EXAMPLES_PWM_DUTYPCT3,
#endif
#if CONFIG_PWM_NCHANNELS > 3
CONFIG_EXAMPLES_PWM_DUTYPCT4,
#endif
};
int i;
#endif
printf("Usage: pwm [OPTIONS]\n"); printf("Usage: pwm [OPTIONS]\n");
printf("\nArguments are \"sticky\". For example, once the PWM frequency is\n"); printf("\nArguments are \"sticky\". For example, once the PWM frequency is\n");
printf("specified, that frequency will be re-used until it is changed.\n"); printf("specified, that frequency will be re-used until it is changed.\n");
printf("\n\"sticky\" OPTIONS include:\n"); printf("\n\"sticky\" OPTIONS include:\n");
printf(" [-p devpath] selects the PWM device. " printf(" [-p devpath] selects the PWM device. "
"Default: %s Current: %s\n", "Default: %s Current: %s\n",
CONFIG_EXAMPLES_PWM_DEVPATH, pwm->devpath ? pwm->devpath : "NONE"); CONFIG_EXAMPLES_PWM_DEVPATH, pwm->devpath ? pwm->devpath : "NONE");
printf(" [-f frequency] selects the pulse frequency. " printf(" [-f frequency] selects the pulse frequency. "
"Default: %d Hz Current: %u Hz\n", "Default: %d Hz Current: %u Hz\n",
CONFIG_EXAMPLES_PWM_FREQUENCY, pwm->freq); CONFIG_EXAMPLES_PWM_FREQUENCY, pwm->freq);
#ifdef CONFIG_PWM_MULTICHAN
printf(" [[-c channel1] [[-c channel2] ...]] selects the channel number for each channel. ");
printf("Default:");
for (i = 0; i < CONFIG_PWM_MULTICHAN; i++)
{
printf(" %d", channels[i]);
}
printf("Current:");
for (i = 0; i < CONFIG_PWM_MULTICHAN; i++)
{
printf(" %d", pwm->channels[i]);
}
printf(" [[-d duty1] [[-d duty2] ...]] selects the pulse duty as a percentage. ");
printf("Default:");
for (i = 0; i < CONFIG_PWM_MULTICHAN; i++)
{
printf(" %d %%", duties[i]);
}
printf("Current:");
for (i = 0; i < CONFIG_PWM_MULTICHAN; i++)
{
printf(" %d %%", pwm->duties[i]);
}
#else
printf(" [-d duty] selects the pulse duty as a percentage. " printf(" [-d duty] selects the pulse duty as a percentage. "
"Default: %d %% Current: %d %%\n", "Default: %d %% Current: %d %%\n",
CONFIG_EXAMPLES_PWM_DUTYPCT, pwm->duty); CONFIG_EXAMPLES_PWM_DUTYPCT, pwm->duty);
#endif
#ifdef CONFIG_PWM_PULSECOUNT #ifdef CONFIG_PWM_PULSECOUNT
printf(" [-n count] selects the pulse count. " printf(" [-n count] selects the pulse count. "
"Default: %d Current: %u\n", "Default: %d Current: %u\n",
CONFIG_EXAMPLES_PWM_PULSECOUNT, pwm->count); CONFIG_EXAMPLES_PWM_PULSECOUNT, pwm->count);
#endif #endif
printf(" [-t duration] is the duration of the pulse train in seconds. " printf(" [-t duration] is the duration of the pulse train in seconds. "
"Default: %d Current: %d\n", "Default: %d Current: %d\n",
CONFIG_EXAMPLES_PWM_DURATION, pwm->duration); CONFIG_EXAMPLES_PWM_DURATION, pwm->duration);
printf(" [-h] shows this message and exits\n"); printf(" [-h] shows this message and exits\n");
} }
@ -186,6 +269,10 @@ static void parse_args(FAR struct pwm_state_s *pwm, int argc, FAR char **argv)
long value; long value;
int index; int index;
int nargs; int nargs;
#ifdef CONFIG_PWM_MULTICHAN
int nchannels = 0;
int nduties = 0;
#endif
for (index = 1; index < argc; ) for (index = 1; index < argc; )
{ {
@ -210,6 +297,29 @@ static void parse_args(FAR struct pwm_state_s *pwm, int argc, FAR char **argv)
index += nargs; index += nargs;
break; break;
#ifdef CONFIG_PWM_MULTICHAN
case 'c':
nargs = arg_decimal(&argv[index], &value);
if (value < 1 || value > 4)
{
printf("Channel out of range: %ld\n", value);
exit(1);
}
if (nchannels < CONFIG_PWM_NCHANNELS)
{
nchannels++;
}
else
{
memmove(pwm->channels, pwm->channels+1, CONFIG_PWM_NCHANNELS-1);
}
pwm->channels[nchannels-1] = (uint8_t)value;
index += nargs;
break;
#endif
case 'd': case 'd':
nargs = arg_decimal(&argv[index], &value); nargs = arg_decimal(&argv[index], &value);
if (value < 1 || value > 99) if (value < 1 || value > 99)
@ -218,7 +328,20 @@ static void parse_args(FAR struct pwm_state_s *pwm, int argc, FAR char **argv)
exit(1); exit(1);
} }
#ifdef CONFIG_PWM_MULTICHAN
if (nduties < CONFIG_PWM_NCHANNELS)
{
nduties++;
}
else
{
memmove(pwm->duties, pwm->duties+1, CONFIG_PWM_NCHANNELS-1);
}
pwm->duties[nduties-1] = (uint8_t)value;
#else
pwm->duty = (uint8_t)value; pwm->duty = (uint8_t)value;
#endif
index += nargs; index += nargs;
break; break;
@ -234,8 +357,8 @@ static void parse_args(FAR struct pwm_state_s *pwm, int argc, FAR char **argv)
pwm->count = (uint32_t)value; pwm->count = (uint32_t)value;
index += nargs; index += nargs;
break; break;
#endif #endif
case 'p': case 'p':
nargs = arg_string(&argv[index], &str); nargs = arg_string(&argv[index], &str);
pwm_devpath(pwm, str); pwm_devpath(pwm, str);
@ -283,12 +406,33 @@ int pwm_main(int argc, char *argv[])
struct pwm_info_s info; struct pwm_info_s info;
int fd; int fd;
int ret; int ret;
#ifdef CONFIG_PWM_MULTICHAN
int i;
int j;
#endif
/* Initialize the state data */ /* Initialize the state data */
if (!g_pwmstate.initialized) if (!g_pwmstate.initialized)
{ {
#ifdef CONFIG_PWM_MULTICHAN
g_pwmstate.channels[0] = CONFIG_EXAMPLES_PWM_CHANNEL1;
g_pwmstate.duties[0] = CONFIG_EXAMPLES_PWM_DUTYPCT1;
#if CONFIG_PWM_NCHANNELS > 1
g_pwmstate.channels[1] = CONFIG_EXAMPLES_PWM_CHANNEL2;
g_pwmstate.duties[1] = CONFIG_EXAMPLES_PWM_DUTYPCT2;
#endif
#if CONFIG_PWM_NCHANNELS > 2
g_pwmstate.channels[2] = CONFIG_EXAMPLES_PWM_CHANNEL3;
g_pwmstate.duties[2] = CONFIG_EXAMPLES_PWM_DUTYPCT3;
#endif
#if CONFIG_PWM_NCHANNELS > 3
g_pwmstate.channels[3] = CONFIG_EXAMPLES_PWM_CHANNEL4;
g_pwmstate.duties[3] = CONFIG_EXAMPLES_PWM_DUTYPCT4;
#endif
#else
g_pwmstate.duty = CONFIG_EXAMPLES_PWM_DUTYPCT; g_pwmstate.duty = CONFIG_EXAMPLES_PWM_DUTYPCT;
#endif
g_pwmstate.freq = CONFIG_EXAMPLES_PWM_FREQUENCY; g_pwmstate.freq = CONFIG_EXAMPLES_PWM_FREQUENCY;
g_pwmstate.duration = CONFIG_EXAMPLES_PWM_DURATION; g_pwmstate.duration = CONFIG_EXAMPLES_PWM_DURATION;
#ifdef CONFIG_PWM_PULSECOUNT #ifdef CONFIG_PWM_PULSECOUNT
@ -301,6 +445,20 @@ int pwm_main(int argc, char *argv[])
parse_args(&g_pwmstate, argc, argv); parse_args(&g_pwmstate, argc, argv);
#ifdef CONFIG_PWM_MULTICHAN
for (i = 0; i < CONFIG_PWM_MULTICHAN; i++)
{
for (j = i + 1; j < CONFIG_PWM_MULTICHAN; j++)
{
if (g_pwmstate.channels[j] == g_pwmstate.channels[i])
{
printf("pwm_main: channel numbers must be unique\n");
goto errout;
}
}
}
#endif
/* Has a device been assigned? */ /* Has a device been assigned? */
if (!g_pwmstate.devpath) if (!g_pwmstate.devpath)
@ -333,17 +491,33 @@ int pwm_main(int argc, char *argv[])
/* Configure the characteristics of the pulse train */ /* Configure the characteristics of the pulse train */
info.frequency = g_pwmstate.freq; info.frequency = g_pwmstate.freq;
#ifdef CONFIG_PWM_MULTICHAN
printf("pwm_main: starting output with frequency: %u",
info.frequency);
for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
{
info.channels[i].channel = g_pwmstate.channels[i];
info.channels[i].duty = ((uint32_t)g_pwmstate.duties[i] << 16) / 100;
printf(" channel: %d duty: %08x",
info.channels[i].channel, info.channels[i].duty);
}
printf("\n");
#else
info.duty = ((uint32_t)g_pwmstate.duty << 16) / 100; info.duty = ((uint32_t)g_pwmstate.duty << 16) / 100;
#ifdef CONFIG_PWM_PULSECOUNT # ifdef CONFIG_PWM_PULSECOUNT
info.count = g_pwmstate.count; info.count = g_pwmstate.count;
printf("pwm_main: starting output with frequency: %u duty: %08x count: %u\n", printf("pwm_main: starting output with frequency: %u duty: %08x count: %u\n",
info.frequency, info.duty, info.count); info.frequency, info.duty, info.count);
#else # else
printf("pwm_main: starting output with frequency: %u duty: %08x\n", printf("pwm_main: starting output with frequency: %u duty: %08x\n",
info.frequency, info.duty); info.frequency, info.duty);
# endif
#endif #endif
ret = ioctl(fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&info)); ret = ioctl(fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&info));
@ -376,7 +550,7 @@ int pwm_main(int argc, char *argv[])
sleep(g_pwmstate.duration); sleep(g_pwmstate.duration);
/* Then stop the pulse train */ /* Then stop the pulse train */
printf("pwm_main: stopping output\n"); printf("pwm_main: stopping output\n");