From 928b49c2d02448fb216bfc71ac74fb8f906361bc Mon Sep 17 00:00:00 2001 From: CYFS <2805686936@qq.com> Date: Wed, 26 Aug 2026 11:02:37 +0800 Subject: [PATCH] [utest][pwm] Add configurable PWM matrix test --- components/drivers/misc/SConscript | 6 + components/drivers/misc/utest/Kconfig | 39 ++ components/drivers/misc/utest/SConscript | 13 + components/drivers/misc/utest/pwm_tc.c | 629 ++++++++++++++++++ components/drivers/misc/utest/pwm_tc_config.h | 177 +++++ components/utilities/utest/Kconfig | 1 + 6 files changed, 865 insertions(+) create mode 100644 components/drivers/misc/utest/Kconfig create mode 100644 components/drivers/misc/utest/SConscript create mode 100644 components/drivers/misc/utest/pwm_tc.c create mode 100644 components/drivers/misc/utest/pwm_tc_config.h diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript index 23727a5ce9b2..83494a6bab81 100644 --- a/components/drivers/misc/SConscript +++ b/components/drivers/misc/SConscript @@ -1,3 +1,4 @@ +import os from building import * cwd = GetCurrentDir() @@ -29,4 +30,9 @@ if GetDepend(['RT_USING_RANDOM']): if len(src): group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) +list = os.listdir(cwd) +for item in list: + if os.path.isfile(os.path.join(cwd, item, 'SConscript')): + group = group + SConscript(os.path.join(item, 'SConscript')) + Return('group') diff --git a/components/drivers/misc/utest/Kconfig b/components/drivers/misc/utest/Kconfig new file mode 100644 index 000000000000..f8f8f873e472 --- /dev/null +++ b/components/drivers/misc/utest/Kconfig @@ -0,0 +1,39 @@ +menu "PWM Test" + +config RT_UTEST_PWM + bool "PWM Frequency and Duty-cycle Matrix Test" + default n + select RT_USING_PWM + help + Run configurable PWM groups. Channels in one group run concurrently, + while groups run in order. Each channel can keep a fixed output, sweep + once and hold its last point, or repeat its sweep for the group duration. + +if RT_UTEST_PWM + +config RT_PWM_TC_CONFIG_FILE + string "PWM test configuration header" + default "pwm_tc_config.h" + help + The header defines PWM_TC_GROUPS and PWM_TC_GROUP_COUNT. Keep the + default for the built-in example, or provide a board-specific header + from a compiler include path. Channel enable switches, device names, + channel numbers, output modes, and waveform points are kept in that + header because Kconfig cannot represent dynamic group/channel arrays. + +config RT_PWM_TC_MAX_CHANNELS + int "Maximum concurrent channels in one PWM test group" + range 1 64 + default 8 + help + This limits enabled channels, not the total number of configured and + disabled channel entries in a group. + +config RT_PWM_TC_TIMEOUT + int "PWM test timeout in seconds" + range 1 3600 + default 30 + +endif + +endmenu diff --git a/components/drivers/misc/utest/SConscript b/components/drivers/misc/utest/SConscript new file mode 100644 index 000000000000..5dbf8b462979 --- /dev/null +++ b/components/drivers/misc/utest/SConscript @@ -0,0 +1,13 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd, cwd + '/../../include'] + +if GetDepend(['RT_UTEST_PWM']): + src += ['pwm_tc.c'] + +group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES', 'RT_USING_PWM'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/misc/utest/pwm_tc.c b/components/drivers/misc/utest/pwm_tc.c new file mode 100644 index 000000000000..d4f0ab66f5aa --- /dev/null +++ b/components/drivers/misc/utest/pwm_tc.c @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-08-25 RT-Thread add configurable PWM matrix utest + */ + +/** + * Test Case Name: PWM Frequency and Duty-cycle Matrix Test + * + * Test Objectives: + * - Validate PWM set, enable, optional get, and disable operations over a + * configurable frequency and duty-cycle matrix. + * - Run multiple PWM channels concurrently and multiple test groups in order. + * - Support fixed output, one-shot sweep with final-value hold, and repeated + * sweep modes independently for every channel. + * + * Dependencies: + * - Requires RT_UTEST_PWM and board PWM devices/pinmux matching the selected + * configuration header. + * - Channels that share one hardware timer period must use compatible + * frequencies while they are active in the same group. + * - Physical frequency and duty-cycle accuracy still requires an oscilloscope, + * logic analyzer, or external capture input. + */ + +#include +#include +#include +#include "utest.h" + +#ifdef RT_UTEST_PWM + +#define PWM_TC_NSEC_PER_SEC 1000000000ULL +#define PWM_TC_DUTY_SCALE 10000U +#define PWM_TC_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +#define PWM_TC_POINT(frequency, duty) \ + { (frequency), (duty) } +#define PWM_TC_POINT_PERCENT(frequency, duty_percent) \ + PWM_TC_POINT((frequency), (duty_percent) * 100U) +#define PWM_TC_CHANNEL_CONFIG(is_enabled, device, channel_number, output_mode, \ + point_table, interval_ms, tolerance) \ + { \ + (is_enabled), (device), (channel_number), (output_mode), \ + (point_table), PWM_TC_ARRAY_SIZE(point_table), (interval_ms), \ + (tolerance) \ + } + +enum pwm_tc_mode +{ + PWM_TC_MODE_FIXED = 0, + PWM_TC_MODE_SWEEP_ONCE, + PWM_TC_MODE_SWEEP_LOOP, +}; + +struct pwm_tc_point +{ + rt_uint32_t frequency_hz; + rt_uint32_t duty_permyriad; +}; + +struct pwm_tc_channel +{ + rt_bool_t enabled; + const char *device_name; + int channel; + enum pwm_tc_mode mode; + const struct pwm_tc_point *points; + rt_size_t point_count; + rt_uint32_t step_interval_ms; + rt_uint32_t readback_tolerance; +}; + +struct pwm_tc_group +{ + const char *name; + const struct pwm_tc_channel *channels; + rt_size_t channel_count; + rt_uint32_t duration_ms; +}; + +#include RT_PWM_TC_CONFIG_FILE + +#ifndef PWM_TC_GROUPS +#error "The PWM test configuration must define PWM_TC_GROUPS" +#endif + +#ifndef PWM_TC_GROUP_COUNT +#error "The PWM test configuration must define PWM_TC_GROUP_COUNT" +#endif + +struct pwm_tc_runtime +{ + const struct pwm_tc_channel *config; + struct rt_device_pwm *device; + rt_size_t point_index; + rt_tick_t last_update_tick; + rt_bool_t enabled; +}; + +static struct pwm_tc_runtime pwm_tc_runtime[RT_PWM_TC_MAX_CHANNELS]; +static rt_size_t pwm_tc_active_count; + +static rt_tick_t pwm_tc_millisecond_to_tick(rt_uint32_t millisecond) +{ + rt_tick_t tick; + + tick = rt_tick_from_millisecond(millisecond); + if (tick == 0) + { + tick = 1; + } + + return tick; +} + +static rt_uint32_t pwm_tc_channel_number(int channel) +{ + if (channel < 0) + { + return (rt_uint32_t)(-channel); + } + + return (rt_uint32_t)channel; +} + +static rt_err_t pwm_tc_point_to_output(const struct pwm_tc_point *point, + rt_uint32_t *period, + rt_uint32_t *pulse) +{ + rt_uint64_t calculated_period; + rt_uint64_t calculated_pulse; + + if (point->frequency_hz == 0 || point->duty_permyriad > PWM_TC_DUTY_SCALE) + { + return -RT_EINVAL; + } + + calculated_period = (PWM_TC_NSEC_PER_SEC + point->frequency_hz / 2U) / + point->frequency_hz; + if (calculated_period == 0 || calculated_period > 0xFFFFFFFFULL) + { + return -RT_EINVAL; + } + + calculated_pulse = (calculated_period * point->duty_permyriad + + PWM_TC_DUTY_SCALE / 2U) / + PWM_TC_DUTY_SCALE; + if (calculated_pulse > calculated_period) + { + calculated_pulse = calculated_period; + } + + *period = (rt_uint32_t)calculated_period; + *pulse = (rt_uint32_t)calculated_pulse; + + return RT_EOK; +} + +static rt_bool_t pwm_tc_value_in_tolerance(rt_uint32_t actual, + rt_uint32_t expected, + rt_uint32_t tolerance) +{ + rt_uint64_t difference; + + if (expected == 0) + { + return actual == 0; + } + + difference = (actual > expected) ? (actual - expected) : (expected - actual); + + return difference * PWM_TC_DUTY_SCALE <= + (rt_uint64_t)expected * tolerance; +} + +static rt_err_t pwm_tc_verify_output(struct pwm_tc_runtime *runtime, + rt_uint32_t period, + rt_uint32_t pulse) +{ + rt_err_t result; + struct rt_pwm_configuration configuration; + const struct pwm_tc_channel *channel; + + channel = runtime->config; + if (channel->readback_tolerance == 0) + { + return RT_EOK; + } + + rt_memset(&configuration, 0, sizeof(configuration)); + configuration.channel = pwm_tc_channel_number(channel->channel); + result = rt_pwm_get(runtime->device, &configuration); + if (result != RT_EOK) + { + LOG_E("PWM readback failed: device=%s channel=%d result=%d", + channel->device_name, channel->channel, result); + return result; + } + + if (!pwm_tc_value_in_tolerance(configuration.period, period, + channel->readback_tolerance) || + !pwm_tc_value_in_tolerance(configuration.pulse, pulse, + channel->readback_tolerance)) + { + LOG_E("PWM readback mismatch: device=%s channel=%d expected=%u/%u ns actual=%u/%u ns", + channel->device_name, channel->channel, + period, pulse, configuration.period, configuration.pulse); + return -RT_ERROR; + } + + return RT_EOK; +} + +static rt_err_t pwm_tc_apply_point(struct pwm_tc_runtime *runtime, + rt_size_t point_index) +{ + rt_err_t result; + rt_uint32_t period; + rt_uint32_t pulse; + const struct pwm_tc_channel *channel; + const struct pwm_tc_point *point; + + channel = runtime->config; + point = &channel->points[point_index]; + result = pwm_tc_point_to_output(point, &period, &pulse); + if (result != RT_EOK) + { + return result; + } + + result = rt_pwm_set(runtime->device, channel->channel, period, pulse); + if (result != RT_EOK) + { + LOG_E("PWM set failed: device=%s channel=%d frequency=%u Hz duty=%u.%02u%% result=%d", + channel->device_name, channel->channel, point->frequency_hz, + point->duty_permyriad / 100U, point->duty_permyriad % 100U, + result); + return result; + } + + result = pwm_tc_verify_output(runtime, period, pulse); + if (result != RT_EOK) + { + return result; + } + + if (!runtime->enabled) + { + result = rt_pwm_enable(runtime->device, channel->channel); + if (result != RT_EOK) + { + LOG_E("PWM enable failed: device=%s channel=%d result=%d", + channel->device_name, channel->channel, result); + return result; + } + runtime->enabled = RT_TRUE; + } + + runtime->point_index = point_index; + runtime->last_update_tick = rt_tick_get(); + LOG_I("PWM output: device=%s channel=%d frequency=%u Hz duty=%u.%02u%%", + channel->device_name, channel->channel, point->frequency_hz, + point->duty_permyriad / 100U, point->duty_permyriad % 100U); + + return RT_EOK; +} + +static rt_bool_t pwm_tc_channel_has_next(const struct pwm_tc_runtime *runtime) +{ + const struct pwm_tc_channel *channel; + + channel = runtime->config; + if (channel->mode == PWM_TC_MODE_SWEEP_LOOP) + { + return channel->point_count > 1; + } + if (channel->mode == PWM_TC_MODE_SWEEP_ONCE) + { + return runtime->point_index + 1 < channel->point_count; + } + + return RT_FALSE; +} + +static rt_size_t pwm_tc_next_point_index(const struct pwm_tc_runtime *runtime) +{ + rt_size_t next; + + next = runtime->point_index + 1; + if (next >= runtime->config->point_count) + { + next = 0; + } + + return next; +} + +static rt_err_t pwm_tc_stop_active_channels(void) +{ + rt_err_t result; + rt_err_t operation_result; + rt_size_t index; + rt_bool_t all_stopped; + + result = RT_EOK; + all_stopped = RT_TRUE; + for (index = 0; index < pwm_tc_active_count; index++) + { + if (!pwm_tc_runtime[index].enabled) + { + continue; + } + + operation_result = rt_pwm_disable(pwm_tc_runtime[index].device, + pwm_tc_runtime[index].config->channel); + if (operation_result != RT_EOK) + { + LOG_E("PWM disable failed: device=%s channel=%d result=%d", + pwm_tc_runtime[index].config->device_name, + pwm_tc_runtime[index].config->channel, + operation_result); + if (result == RT_EOK) + { + result = operation_result; + } + all_stopped = RT_FALSE; + } + else + { + pwm_tc_runtime[index].enabled = RT_FALSE; + } + } + if (all_stopped) + { + pwm_tc_active_count = 0; + } + + return result; +} + +static rt_err_t pwm_tc_start_group(const struct pwm_tc_group *group) +{ + rt_err_t result; + rt_size_t index; + rt_device_t device; + struct pwm_tc_runtime *runtime; + + rt_memset(pwm_tc_runtime, 0, sizeof(pwm_tc_runtime)); + pwm_tc_active_count = 0; + + for (index = 0; index < group->channel_count; index++) + { + if (!group->channels[index].enabled) + { + continue; + } + + device = rt_device_find(group->channels[index].device_name); + runtime = &pwm_tc_runtime[pwm_tc_active_count]; + runtime->config = &group->channels[index]; + runtime->device = (struct rt_device_pwm *)device; + pwm_tc_active_count++; + + result = pwm_tc_apply_point(runtime, 0); + if (result != RT_EOK) + { + pwm_tc_stop_active_channels(); + return result; + } + } + + return RT_EOK; +} + +static rt_err_t pwm_tc_run_group(const struct pwm_tc_group *group) +{ + rt_err_t result; + rt_err_t stop_result; + rt_size_t index; + rt_tick_t duration_tick; + rt_tick_t elapsed_tick; + rt_tick_t interval_tick; + rt_tick_t since_update_tick; + rt_tick_t sleep_tick; + rt_tick_t start_tick; + + result = pwm_tc_start_group(group); + if (result != RT_EOK) + { + return result; + } + LOG_I("PWM group started: name=%s enabled=%u configured=%u duration=%u ms", + group->name, (unsigned int)pwm_tc_active_count, + (unsigned int)group->channel_count, group->duration_ms); + + start_tick = rt_tick_get(); + duration_tick = pwm_tc_millisecond_to_tick(group->duration_ms); + while ((elapsed_tick = rt_tick_get_delta(start_tick)) < duration_tick) + { + sleep_tick = duration_tick - elapsed_tick; + for (index = 0; index < pwm_tc_active_count; index++) + { + if (!pwm_tc_channel_has_next(&pwm_tc_runtime[index])) + { + continue; + } + + interval_tick = pwm_tc_millisecond_to_tick( + pwm_tc_runtime[index].config->step_interval_ms); + since_update_tick = rt_tick_get_delta( + pwm_tc_runtime[index].last_update_tick); + if (since_update_tick >= interval_tick) + { + result = pwm_tc_apply_point(&pwm_tc_runtime[index], + pwm_tc_next_point_index( + &pwm_tc_runtime[index])); + if (result != RT_EOK) + { + goto __exit; + } + since_update_tick = 0; + } + + if (interval_tick - since_update_tick < sleep_tick) + { + sleep_tick = interval_tick - since_update_tick; + } + } + + if (sleep_tick == 0) + { + sleep_tick = 1; + } + rt_thread_delay(sleep_tick); + } + +__exit: + stop_result = pwm_tc_stop_active_channels(); + if (result == RT_EOK) + { + result = stop_result; + } + LOG_I("PWM group finished: name=%s result=%d", group->name, result); + + return result; +} + +static rt_err_t pwm_tc_validate_channel(const struct pwm_tc_channel *channel) +{ + rt_err_t result; + rt_size_t index; + rt_uint32_t period; + rt_uint32_t pulse; + rt_device_t device; + + if (channel->device_name == RT_NULL || channel->device_name[0] == '\0' || + channel->points == RT_NULL || channel->point_count == 0 || + channel->channel == INT_MIN || + channel->mode < PWM_TC_MODE_FIXED || + channel->mode > PWM_TC_MODE_SWEEP_LOOP || + channel->readback_tolerance > PWM_TC_DUTY_SCALE) + { + return -RT_EINVAL; + } + if (channel->mode == PWM_TC_MODE_FIXED && channel->point_count != 1) + { + return -RT_EINVAL; + } + if (channel->mode != PWM_TC_MODE_FIXED && channel->point_count > 1 && + channel->step_interval_ms == 0) + { + return -RT_EINVAL; + } + + device = rt_device_find(channel->device_name); + if (device == RT_NULL) + { + LOG_E("PWM device not found: %s", channel->device_name); + return -RT_ENOSYS; + } + if (device->type != RT_Device_Class_PWM) + { + LOG_E("Device is not PWM: %s type=%d", channel->device_name, device->type); + return -RT_EINVAL; + } + + for (index = 0; index < channel->point_count; index++) + { + result = pwm_tc_point_to_output(&channel->points[index], &period, &pulse); + if (result != RT_EOK) + { + LOG_E("Invalid PWM point: device=%s channel=%d point=%u", + channel->device_name, channel->channel, (unsigned int)index); + return result; + } + } + + return RT_EOK; +} + +static rt_err_t pwm_tc_validate_group(const struct pwm_tc_group *group) +{ + rt_err_t result; + rt_size_t index; + rt_size_t peer_index; + rt_size_t enabled_count; + + if (group->name == RT_NULL || group->name[0] == '\0' || + group->channels == RT_NULL || group->channel_count == 0 || + group->duration_ms == 0) + { + return -RT_EINVAL; + } + + enabled_count = 0; + for (index = 0; index < group->channel_count; index++) + { + if (!group->channels[index].enabled) + { + continue; + } + + enabled_count++; + if (enabled_count > RT_PWM_TC_MAX_CHANNELS) + { + LOG_E("Too many enabled PWM channels in group %s: enabled=%u max=%u", + group->name, (unsigned int)enabled_count, + (unsigned int)RT_PWM_TC_MAX_CHANNELS); + return -RT_EINVAL; + } + + result = pwm_tc_validate_channel(&group->channels[index]); + if (result != RT_EOK) + { + return result; + } + + for (peer_index = 0; peer_index < index; peer_index++) + { + if (!group->channels[peer_index].enabled) + { + continue; + } + + if (group->channels[index].channel == + group->channels[peer_index].channel && + rt_strcmp(group->channels[index].device_name, + group->channels[peer_index].device_name) == 0) + { + LOG_E("Duplicate PWM channel in group %s: device=%s channel=%d", + group->name, group->channels[index].device_name, + group->channels[index].channel); + return -RT_EINVAL; + } + } + } + + if (enabled_count == 0) + { + LOG_E("No PWM channel enabled in group %s", group->name); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void pwm_tc_configuration_matrix(void) +{ + rt_err_t result; + rt_size_t index; + + for (index = 0; index < PWM_TC_GROUP_COUNT; index++) + { + result = pwm_tc_run_group(&PWM_TC_GROUPS[index]); + uassert_int_equal(result, RT_EOK); + if (result != RT_EOK) + { + return; + } + } +} + +static rt_err_t utest_tc_init(void) +{ + rt_err_t result; + rt_size_t index; + + pwm_tc_active_count = 0; + if (PWM_TC_GROUP_COUNT == 0) + { + return -RT_EINVAL; + } + + for (index = 0; index < PWM_TC_GROUP_COUNT; index++) + { + result = pwm_tc_validate_group(&PWM_TC_GROUPS[index]); + if (result != RT_EOK) + { + LOG_E("Invalid PWM group: index=%u result=%d", + (unsigned int)index, result); + return result; + } + } + + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return pwm_tc_stop_active_channels(); +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(pwm_tc_configuration_matrix); +} + +UTEST_TC_EXPORT(testcase, + "components.drivers.pwm.configuration_matrix", + utest_tc_init, + utest_tc_cleanup, + RT_PWM_TC_TIMEOUT); + +#endif /* RT_UTEST_PWM */ diff --git a/components/drivers/misc/utest/pwm_tc_config.h b/components/drivers/misc/utest/pwm_tc_config.h new file mode 100644 index 000000000000..6eb0cd40b2b2 --- /dev/null +++ b/components/drivers/misc/utest/pwm_tc_config.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-08-25 RT-Thread add the default PWM matrix test configuration + */ + +#ifndef __PWM_TC_CONFIG_H__ +#define __PWM_TC_CONFIG_H__ + +/* + * Channel catalog + * + * Set ENABLED to RT_TRUE to include a channel in every group below, or + * RT_FALSE to skip it. Disabled channels are not looked up or started. + * READBACK_TOLERANCE is in permyriad; 0 disables PWM_CMD_GET verification. + * The default enables only channel 1, which sweeps continuously in each group. + */ +#define PWM_TC_CFG_CHANNEL_1_ENABLED RT_TRUE +#define PWM_TC_CFG_CHANNEL_1_DEVICE_NAME "pwm12" +#define PWM_TC_CFG_CHANNEL_1_NUMBER 0 +#define PWM_TC_CFG_CHANNEL_1_READBACK_TOLERANCE 500U + +#define PWM_TC_CFG_CHANNEL_2_ENABLED RT_FALSE +#define PWM_TC_CFG_CHANNEL_2_DEVICE_NAME "pwm2" +#define PWM_TC_CFG_CHANNEL_2_NUMBER 1 +#define PWM_TC_CFG_CHANNEL_2_READBACK_TOLERANCE 0U + +#define PWM_TC_CFG_CHANNEL_3_ENABLED RT_FALSE +#define PWM_TC_CFG_CHANNEL_3_DEVICE_NAME "pwm3" +#define PWM_TC_CFG_CHANNEL_3_NUMBER 1 +#define PWM_TC_CFG_CHANNEL_3_READBACK_TOLERANCE 0U + +#define PWM_TC_CFG_CHANNEL_4_ENABLED RT_FALSE +#define PWM_TC_CFG_CHANNEL_4_DEVICE_NAME "pwm4" +#define PWM_TC_CFG_CHANNEL_4_NUMBER 1 +#define PWM_TC_CFG_CHANNEL_4_READBACK_TOLERANCE 0U + +/* Group timing */ +#define PWM_TC_CFG_GROUP_1_DURATION_MS 2000U +#define PWM_TC_CFG_GROUP_2_DURATION_MS 1000U + +/* + * Waveform point tables + * + * PWM_TC_POINT_PERCENT takes frequency in Hz and duty cycle in percent. + * PWM_TC_POINT takes frequency in Hz and duty cycle in permyriad. + */ +static const struct pwm_tc_point pwm_tc_channel_1_sweep_points[] = { + PWM_TC_POINT_PERCENT(2500, 10), + PWM_TC_POINT_PERCENT(2500, 50), + PWM_TC_POINT_PERCENT(5000, 25), + PWM_TC_POINT_PERCENT(5000, 75), +}; + +static const struct pwm_tc_point pwm_tc_channel_2_sweep_points[] = { + PWM_TC_POINT_PERCENT(500, 20), + PWM_TC_POINT_PERCENT(1500, 40), + PWM_TC_POINT_PERCENT(4000, 60), +}; + +static const struct pwm_tc_point pwm_tc_channel_2_fixed_points[] = { + PWM_TC_POINT_PERCENT(10000, 65), +}; + +static const struct pwm_tc_point pwm_tc_channel_3_sweep_points[] = { + PWM_TC_POINT_PERCENT(800, 15), + PWM_TC_POINT_PERCENT(1800, 35), + PWM_TC_POINT_PERCENT(3200, 55), +}; + +static const struct pwm_tc_point pwm_tc_channel_3_fixed_points[] = { + PWM_TC_POINT_PERCENT(6000, 30), +}; + +static const struct pwm_tc_point pwm_tc_channel_4_sweep_points[] = { + PWM_TC_POINT_PERCENT(1200, 25), + PWM_TC_POINT_PERCENT(2400, 50), + PWM_TC_POINT_PERCENT(4800, 75), +}; + +static const struct pwm_tc_point pwm_tc_channel_4_fixed_points[] = { + PWM_TC_POINT_PERCENT(8000, 70), +}; + +/* + * Group 1 channel behavior + * + * Channels in a group run concurrently. Each channel selects its own output + * mode, point table, and step interval in milliseconds. + */ +static const struct pwm_tc_channel pwm_tc_group_1_channels[] = { + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_1_ENABLED, + PWM_TC_CFG_CHANNEL_1_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_1_NUMBER, + PWM_TC_MODE_SWEEP_LOOP, + pwm_tc_channel_1_sweep_points, + 200U, + PWM_TC_CFG_CHANNEL_1_READBACK_TOLERANCE), + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_2_ENABLED, + PWM_TC_CFG_CHANNEL_2_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_2_NUMBER, + PWM_TC_MODE_FIXED, + pwm_tc_channel_2_fixed_points, + 0U, + PWM_TC_CFG_CHANNEL_2_READBACK_TOLERANCE), + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_3_ENABLED, + PWM_TC_CFG_CHANNEL_3_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_3_NUMBER, + PWM_TC_MODE_SWEEP_ONCE, + pwm_tc_channel_3_sweep_points, + 250U, + PWM_TC_CFG_CHANNEL_3_READBACK_TOLERANCE), + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_4_ENABLED, + PWM_TC_CFG_CHANNEL_4_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_4_NUMBER, + PWM_TC_MODE_FIXED, + pwm_tc_channel_4_fixed_points, + 0U, + PWM_TC_CFG_CHANNEL_4_READBACK_TOLERANCE), +}; + +/* Group 2 channel behavior */ +static const struct pwm_tc_channel pwm_tc_group_2_channels[] = { + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_1_ENABLED, + PWM_TC_CFG_CHANNEL_1_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_1_NUMBER, + PWM_TC_MODE_SWEEP_LOOP, + pwm_tc_channel_1_sweep_points, + 200U, + PWM_TC_CFG_CHANNEL_1_READBACK_TOLERANCE), + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_2_ENABLED, + PWM_TC_CFG_CHANNEL_2_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_2_NUMBER, + PWM_TC_MODE_SWEEP_ONCE, + pwm_tc_channel_2_sweep_points, + 300U, + PWM_TC_CFG_CHANNEL_2_READBACK_TOLERANCE), + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_3_ENABLED, + PWM_TC_CFG_CHANNEL_3_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_3_NUMBER, + PWM_TC_MODE_FIXED, + pwm_tc_channel_3_fixed_points, + 0U, + PWM_TC_CFG_CHANNEL_3_READBACK_TOLERANCE), + PWM_TC_CHANNEL_CONFIG(PWM_TC_CFG_CHANNEL_4_ENABLED, + PWM_TC_CFG_CHANNEL_4_DEVICE_NAME, + PWM_TC_CFG_CHANNEL_4_NUMBER, + PWM_TC_MODE_SWEEP_LOOP, + pwm_tc_channel_4_sweep_points, + 350U, + PWM_TC_CFG_CHANNEL_4_READBACK_TOLERANCE), +}; + +/* Test group list; groups run in array order. */ +static const struct pwm_tc_group pwm_tc_groups[] = { + { + "mixed-output-loop", + pwm_tc_group_1_channels, + PWM_TC_ARRAY_SIZE(pwm_tc_group_1_channels), + PWM_TC_CFG_GROUP_1_DURATION_MS, + }, + { + "mixed-output-sweep", + pwm_tc_group_2_channels, + PWM_TC_ARRAY_SIZE(pwm_tc_group_2_channels), + PWM_TC_CFG_GROUP_2_DURATION_MS, + }, +}; + +#define PWM_TC_GROUPS pwm_tc_groups +#define PWM_TC_GROUP_COUNT PWM_TC_ARRAY_SIZE(pwm_tc_groups) + +#endif /* __PWM_TC_CONFIG_H__ */ diff --git a/components/utilities/utest/Kconfig b/components/utilities/utest/Kconfig index f2bb5f6f8879..456a9e46517a 100644 --- a/components/utilities/utest/Kconfig +++ b/components/utilities/utest/Kconfig @@ -16,6 +16,7 @@ menu "RT-Thread Utestcases" rsource "../../../components/drivers/core/utest/Kconfig" rsource "../../../components/drivers/audio/utest/Kconfig" rsource "../../../components/drivers/ipc/utest/Kconfig" + rsource "../../../components/drivers/misc/utest/Kconfig" rsource "../../../components/drivers/pin/utest/Kconfig" rsource "../../../components/drivers/serial/utest/Kconfig" rsource "../../../components/drivers/smp_call/utest/Kconfig"