tests: drivers: pwm: add PWM loopback test
Add test cases for the PWM capture API using PWM signal loopback. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
parent
54fed42f23
commit
90825a8812
8 changed files with 501 additions and 0 deletions
9
tests/drivers/pwm/pwm_loopback/CMakeLists.txt
Normal file
9
tests/drivers/pwm/pwm_loopback/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(pwm_loopback)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
15
tests/drivers/pwm/pwm_loopback/boards/frdm_k64f.overlay
Normal file
15
tests/drivers/pwm/pwm_loopback/boards/frdm_k64f.overlay
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Vestas Wind Systems A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <dt-bindings/pwm/pwm.h>
|
||||
|
||||
/ {
|
||||
pwm_loopback_0 {
|
||||
compatible = "test,pwm_loopback";
|
||||
pwms = <&ftm0 0 0 PWM_POLARITY_NORMAL>, /* PTC1, J1 pin 5 */
|
||||
<&ftm3 4 0 PWM_POLARITY_NORMAL>; /* PTC8, J1 pin 7 */
|
||||
};
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright (c) 2020-2021 Vestas Wind Systems A/S
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
description: |
|
||||
This binding provides resources required to build and run the
|
||||
tests/drivers/pwm/pwm_loopback test in Zephyr.
|
||||
|
||||
compatible: "test,pwm_loopback"
|
||||
|
||||
properties:
|
||||
pwms:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: |
|
||||
PWM pins that will be used for generating and capturing a pulse-width
|
||||
modulated signal. The pin at the first index will be used for signal
|
||||
generation while the pin at the second index will be used for capuring
|
||||
the generated signal. The two pins must be physically connected to
|
||||
each other.
|
5
tests/drivers/pwm/pwm_loopback/prj.conf
Normal file
5
tests/drivers/pwm/pwm_loopback/prj.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_TEST_USERSPACE=y
|
||||
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_CAPTURE=y
|
32
tests/drivers/pwm/pwm_loopback/src/main.c
Normal file
32
tests/drivers/pwm/pwm_loopback/src/main.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Vestas Wind Systems A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <ztest.h>
|
||||
|
||||
#include "test_pwm_loopback.h"
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
struct test_pwm in;
|
||||
struct test_pwm out;
|
||||
|
||||
get_test_pwms(&in, &out);
|
||||
|
||||
k_object_access_grant(out.dev, k_current_get());
|
||||
k_object_access_grant(in.dev, k_current_get());
|
||||
|
||||
ztest_test_suite(pwm_loopback_test,
|
||||
ztest_user_unit_test(test_pulse_capture),
|
||||
ztest_user_unit_test(test_pulse_capture_inverted),
|
||||
ztest_user_unit_test(test_period_capture),
|
||||
ztest_user_unit_test(test_period_capture_inverted),
|
||||
ztest_user_unit_test(test_pulse_and_period_capture),
|
||||
ztest_user_unit_test(test_capture_timeout),
|
||||
ztest_unit_test(test_continuous_capture),
|
||||
ztest_unit_test(test_capture_busy));
|
||||
ztest_run_test_suite(pwm_loopback_test);
|
||||
}
|
344
tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.c
Normal file
344
tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Vestas Wind Systems A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <drivers/pwm.h>
|
||||
#include <ztest.h>
|
||||
|
||||
#include "test_pwm_loopback.h"
|
||||
|
||||
#define TEST_PWM_PERIOD_NSEC 100000000
|
||||
#define TEST_PWM_PULSE_NSEC 15000000
|
||||
#define TEST_PWM_PERIOD_USEC 100000
|
||||
#define TEST_PWM_PULSE_USEC 75000
|
||||
|
||||
enum test_pwm_unit {
|
||||
TEST_PWM_UNIT_NSEC,
|
||||
TEST_PWM_UNIT_USEC,
|
||||
};
|
||||
|
||||
void get_test_pwms(struct test_pwm *out, struct test_pwm *in)
|
||||
{
|
||||
/* PWM generator device */
|
||||
out->dev = device_get_binding(PWM_LOOPBACK_OUT_LABEL);
|
||||
out->pwm = PWM_LOOPBACK_OUT_CHANNEL;
|
||||
out->flags = PWM_LOOPBACK_OUT_FLAGS;
|
||||
zassert_not_null(out->dev, "pwm loopback output device not found");
|
||||
|
||||
/* PWM capture device */
|
||||
in->dev = device_get_binding(PWM_LOOPBACK_IN_LABEL);
|
||||
in->pwm = PWM_LOOPBACK_IN_CHANNEL;
|
||||
in->flags = PWM_LOOPBACK_IN_FLAGS;
|
||||
zassert_not_null(in->dev, "pwm loopback input device not found");
|
||||
}
|
||||
|
||||
void test_capture(uint32_t period, uint32_t pulse, enum test_pwm_unit unit,
|
||||
pwm_flags_t flags)
|
||||
{
|
||||
struct test_pwm in;
|
||||
struct test_pwm out;
|
||||
uint64_t period_capture = 0;
|
||||
uint64_t pulse_capture = 0;
|
||||
int err = 0;
|
||||
|
||||
get_test_pwms(&out, &in);
|
||||
|
||||
switch (unit) {
|
||||
case TEST_PWM_UNIT_NSEC:
|
||||
TC_PRINT("Testing PWM capture @ %u/%u nsec\n",
|
||||
pulse, period);
|
||||
err = pwm_pin_set_nsec(out.dev, out.pwm, period,
|
||||
pulse, out.flags);
|
||||
break;
|
||||
|
||||
case TEST_PWM_UNIT_USEC:
|
||||
TC_PRINT("Testing PWM capture @ %u/%u usec\n",
|
||||
pulse, period);
|
||||
err = pwm_pin_set_usec(out.dev, out.pwm, period,
|
||||
pulse, out.flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
TC_PRINT("Unsupported test unit");
|
||||
ztest_test_fail();
|
||||
}
|
||||
|
||||
zassert_equal(err, 0, "failed to set pwm output (err %d)", err);
|
||||
|
||||
switch (unit) {
|
||||
case TEST_PWM_UNIT_NSEC:
|
||||
err = pwm_pin_capture_nsec(in.dev, in.pwm, flags,
|
||||
&period_capture, &pulse_capture,
|
||||
K_NSEC(period * 10));
|
||||
break;
|
||||
|
||||
case TEST_PWM_UNIT_USEC:
|
||||
err = pwm_pin_capture_usec(in.dev, in.pwm, flags,
|
||||
&period_capture, &pulse_capture,
|
||||
K_USEC(period * 10));
|
||||
break;
|
||||
|
||||
default:
|
||||
TC_PRINT("Unsupported test unit");
|
||||
ztest_test_fail();
|
||||
}
|
||||
|
||||
if (err == -ENOTSUP) {
|
||||
TC_PRINT("capture type not supported\n");
|
||||
ztest_test_skip();
|
||||
}
|
||||
|
||||
zassert_equal(err, 0, "failed to capture pwm (err %d)", err);
|
||||
|
||||
if (flags & PWM_CAPTURE_TYPE_PERIOD) {
|
||||
zassert_within(period_capture, period, period / 100,
|
||||
"period capture off by more than 1%");
|
||||
}
|
||||
|
||||
if (flags & PWM_CAPTURE_TYPE_PULSE) {
|
||||
if (flags & PWM_POLARITY_INVERTED) {
|
||||
zassert_within(pulse_capture, period - pulse,
|
||||
(period - pulse) / 100,
|
||||
"pulse capture off by more than 1%");
|
||||
} else {
|
||||
zassert_within(pulse_capture, pulse, pulse / 100,
|
||||
"pulse capture off by more than 1%");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_pulse_capture(void)
|
||||
{
|
||||
test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC,
|
||||
TEST_PWM_UNIT_NSEC,
|
||||
PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_NORMAL);
|
||||
test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC,
|
||||
TEST_PWM_UNIT_USEC,
|
||||
PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_NORMAL);
|
||||
}
|
||||
|
||||
void test_pulse_capture_inverted(void)
|
||||
{
|
||||
test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC,
|
||||
TEST_PWM_UNIT_NSEC,
|
||||
PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_INVERTED);
|
||||
test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC,
|
||||
TEST_PWM_UNIT_USEC,
|
||||
PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_INVERTED);
|
||||
}
|
||||
|
||||
void test_period_capture(void)
|
||||
{
|
||||
test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC,
|
||||
TEST_PWM_UNIT_NSEC,
|
||||
PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_NORMAL);
|
||||
test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC,
|
||||
TEST_PWM_UNIT_USEC,
|
||||
PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_NORMAL);
|
||||
}
|
||||
|
||||
void test_period_capture_inverted(void)
|
||||
{
|
||||
test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC,
|
||||
TEST_PWM_UNIT_NSEC,
|
||||
PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_INVERTED);
|
||||
test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC,
|
||||
TEST_PWM_UNIT_USEC,
|
||||
PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_INVERTED);
|
||||
}
|
||||
|
||||
void test_pulse_and_period_capture(void)
|
||||
{
|
||||
test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC,
|
||||
TEST_PWM_UNIT_NSEC,
|
||||
PWM_CAPTURE_TYPE_BOTH | PWM_POLARITY_NORMAL);
|
||||
test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC,
|
||||
TEST_PWM_UNIT_USEC,
|
||||
PWM_CAPTURE_TYPE_BOTH | PWM_POLARITY_NORMAL);
|
||||
}
|
||||
|
||||
void test_capture_timeout(void)
|
||||
{
|
||||
struct test_pwm in;
|
||||
struct test_pwm out;
|
||||
uint32_t period;
|
||||
uint32_t pulse;
|
||||
int err;
|
||||
|
||||
get_test_pwms(&out, &in);
|
||||
|
||||
err = pwm_pin_set_cycles(out.dev, out.pwm, 100, 0, out.flags);
|
||||
zassert_equal(err, 0, "failed to set pwm output (err %d)", err);
|
||||
|
||||
err = pwm_pin_capture_cycles(in.dev, in.pwm,
|
||||
PWM_CAPTURE_TYPE_PULSE,
|
||||
&period, &pulse, K_MSEC(1000));
|
||||
if (err == -ENOTSUP) {
|
||||
TC_PRINT("Pulse capture not supported, "
|
||||
"trying period capture\n");
|
||||
err = pwm_pin_capture_cycles(in.dev, in.pwm,
|
||||
PWM_CAPTURE_TYPE_PERIOD,
|
||||
&period, &pulse, K_MSEC(1000));
|
||||
}
|
||||
|
||||
zassert_equal(err, -EAGAIN, "pwm capture did not timeout (err %d)",
|
||||
err);
|
||||
}
|
||||
|
||||
static void continuous_capture_callback(const struct device *dev,
|
||||
uint32_t pwm,
|
||||
uint32_t period_cycles,
|
||||
uint32_t pulse_cycles,
|
||||
int status,
|
||||
void *user_data)
|
||||
{
|
||||
struct test_pwm_callback_data *data = user_data;
|
||||
|
||||
if (data->count > data->buffer_len) {
|
||||
/* Safe guard in case capture is not disabled */
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
/* Error occurred */
|
||||
data->status = status;
|
||||
k_sem_give(&data->sem);
|
||||
}
|
||||
|
||||
if (data->pulse_capture) {
|
||||
data->buffer[data->count++] = pulse_cycles;
|
||||
} else {
|
||||
data->buffer[data->count++] = period_cycles;
|
||||
}
|
||||
|
||||
if (data->count > data->buffer_len) {
|
||||
data->status = 0;
|
||||
k_sem_give(&data->sem);
|
||||
}
|
||||
}
|
||||
|
||||
void test_continuous_capture(void)
|
||||
{
|
||||
static const uint32_t period_usec = 10000;
|
||||
static const uint32_t pulse_usec = 7500;
|
||||
struct test_pwm in;
|
||||
struct test_pwm out;
|
||||
uint32_t buffer[10];
|
||||
struct test_pwm_callback_data data = {
|
||||
.buffer = buffer,
|
||||
.buffer_len = ARRAY_SIZE(buffer),
|
||||
.count = 0,
|
||||
.pulse_capture = true,
|
||||
};
|
||||
uint64_t usec = 0;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
get_test_pwms(&out, &in);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
k_sem_init(&data.sem, 0, 1);
|
||||
|
||||
err = pwm_pin_set_usec(out.dev, out.pwm, period_usec, pulse_usec,
|
||||
out.flags);
|
||||
zassert_equal(err, 0, "failed to set pwm output (err %d)", err);
|
||||
|
||||
err = pwm_pin_configure_capture(in.dev, in.pwm,
|
||||
in.flags |
|
||||
PWM_CAPTURE_MODE_CONTINUOUS |
|
||||
PWM_CAPTURE_TYPE_PULSE,
|
||||
continuous_capture_callback,
|
||||
&data);
|
||||
if (err == -ENOTSUP) {
|
||||
TC_PRINT("Pulse capture not supported, "
|
||||
"trying period capture\n");
|
||||
err = pwm_pin_configure_capture(in.dev, in.pwm,
|
||||
in.flags |
|
||||
PWM_CAPTURE_MODE_CONTINUOUS |
|
||||
PWM_CAPTURE_TYPE_PERIOD,
|
||||
continuous_capture_callback,
|
||||
&data);
|
||||
zassert_equal(err, 0, "failed to configure pwm input (err %d)",
|
||||
err);
|
||||
data.pulse_capture = false;
|
||||
}
|
||||
|
||||
err = pwm_pin_enable_capture(in.dev, in.pwm);
|
||||
zassert_equal(err, 0, "failed to enable pwm capture (err %d)", err);
|
||||
|
||||
err = k_sem_take(&data.sem, K_USEC(period_usec * data.buffer_len * 10));
|
||||
zassert_equal(err, 0, "pwm capture timed out (err %d)", err);
|
||||
zassert_equal(data.status, 0, "pwm capture failed (err %d)", err);
|
||||
|
||||
err = pwm_pin_disable_capture(in.dev, in.pwm);
|
||||
zassert_equal(err, 0, "failed to disable pwm capture (err %d)", err);
|
||||
|
||||
for (i = 0; i < data.buffer_len; i++) {
|
||||
err = pwm_pin_cycles_to_usec(in.dev, in.pwm, buffer[i], &usec);
|
||||
zassert_equal(err, 0, "failed to calculate usec (err %d)", err);
|
||||
|
||||
if (data.pulse_capture) {
|
||||
zassert_within(usec, pulse_usec, pulse_usec / 100,
|
||||
"pulse capture off by more than 1%");
|
||||
} else {
|
||||
zassert_within(usec, period_usec, period_usec / 100,
|
||||
"period capture off by more than 1%");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_capture_busy(void)
|
||||
{
|
||||
struct test_pwm in;
|
||||
struct test_pwm out;
|
||||
uint32_t buffer[10];
|
||||
struct test_pwm_callback_data data = {
|
||||
.buffer = buffer,
|
||||
.buffer_len = ARRAY_SIZE(buffer),
|
||||
.count = 0,
|
||||
.pulse_capture = true,
|
||||
};
|
||||
pwm_flags_t flags = PWM_CAPTURE_MODE_SINGLE |
|
||||
PWM_CAPTURE_TYPE_PULSE;
|
||||
int err;
|
||||
|
||||
get_test_pwms(&out, &in);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
k_sem_init(&data.sem, 0, 1);
|
||||
|
||||
err = pwm_pin_set_cycles(out.dev, out.pwm, 100, 0, out.flags);
|
||||
zassert_equal(err, 0, "failed to set pwm output (err %d)", err);
|
||||
|
||||
err = pwm_pin_configure_capture(in.dev, in.pwm,
|
||||
in.flags | flags,
|
||||
continuous_capture_callback,
|
||||
&data);
|
||||
if (err == -ENOTSUP) {
|
||||
TC_PRINT("Pulse capture not supported, "
|
||||
"trying period capture\n");
|
||||
flags = PWM_CAPTURE_MODE_SINGLE | PWM_CAPTURE_TYPE_PERIOD;
|
||||
err = pwm_pin_configure_capture(in.dev, in.pwm,
|
||||
in.flags | flags,
|
||||
continuous_capture_callback,
|
||||
&data);
|
||||
zassert_equal(err, 0, "failed to configure pwm input (err %d)",
|
||||
err);
|
||||
data.pulse_capture = false;
|
||||
}
|
||||
|
||||
err = pwm_pin_enable_capture(in.dev, in.pwm);
|
||||
zassert_equal(err, 0, "failed to enable pwm capture (err %d)", err);
|
||||
|
||||
err = pwm_pin_configure_capture(in.dev, in.pwm,
|
||||
in.flags | flags,
|
||||
continuous_capture_callback,
|
||||
&data);
|
||||
zassert_equal(err, -EBUSY, "pwm capture not busy (err %d)", err);
|
||||
|
||||
err = pwm_pin_disable_capture(in.dev, in.pwm);
|
||||
zassert_equal(err, 0, "failed to disable pwm capture (err %d)", err);
|
||||
}
|
66
tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.h
Normal file
66
tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Vestas Wind Systems A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __TEST_PWM_LOOPBACK_H__
|
||||
#define __TEST_PWM_LOOPBACK_H__
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <drivers/pwm.h>
|
||||
#include <ztest.h>
|
||||
|
||||
#define PWM_LOOPBACK_OUT_IDX 0
|
||||
#define PWM_LOOPBACK_IN_IDX 1
|
||||
|
||||
#define PWM_LOOPBACK_NODE DT_INST(0, test_pwm_loopback)
|
||||
|
||||
#define PWM_LOOPBACK_OUT_LABEL \
|
||||
DT_PWMS_LABEL_BY_IDX(PWM_LOOPBACK_NODE, PWM_LOOPBACK_OUT_IDX)
|
||||
#define PWM_LOOPBACK_OUT_CHANNEL \
|
||||
DT_PWMS_CHANNEL_BY_IDX(PWM_LOOPBACK_NODE, PWM_LOOPBACK_OUT_IDX)
|
||||
#define PWM_LOOPBACK_OUT_FLAGS \
|
||||
DT_PWMS_FLAGS_BY_IDX(PWM_LOOPBACK_NODE, PWM_LOOPBACK_OUT_IDX)
|
||||
|
||||
#define PWM_LOOPBACK_IN_LABEL \
|
||||
DT_PWMS_LABEL_BY_IDX(PWM_LOOPBACK_NODE, PWM_LOOPBACK_IN_IDX)
|
||||
#define PWM_LOOPBACK_IN_CHANNEL \
|
||||
DT_PWMS_CHANNEL_BY_IDX(PWM_LOOPBACK_NODE, PWM_LOOPBACK_IN_IDX)
|
||||
#define PWM_LOOPBACK_IN_FLAGS \
|
||||
DT_PWMS_FLAGS_BY_IDX(PWM_LOOPBACK_NODE, PWM_LOOPBACK_IN_IDX)
|
||||
|
||||
struct test_pwm {
|
||||
const struct device *dev;
|
||||
uint32_t pwm;
|
||||
pwm_flags_t flags;
|
||||
};
|
||||
|
||||
struct test_pwm_callback_data {
|
||||
uint32_t *buffer;
|
||||
size_t buffer_len;
|
||||
size_t count;
|
||||
int status;
|
||||
struct k_sem sem;
|
||||
bool pulse_capture;
|
||||
};
|
||||
|
||||
void get_test_pwms(struct test_pwm *out, struct test_pwm *in);
|
||||
|
||||
void test_pulse_capture(void);
|
||||
|
||||
void test_pulse_capture_inverted(void);
|
||||
|
||||
void test_period_capture(void);
|
||||
|
||||
void test_period_capture_inverted(void);
|
||||
|
||||
void test_pulse_and_period_capture(void);
|
||||
|
||||
void test_capture_timeout(void);
|
||||
|
||||
void test_continuous_capture(void);
|
||||
|
||||
void test_capture_busy(void);
|
||||
|
||||
#endif /* __TEST_PWM_LOOPBACK_H__ */
|
8
tests/drivers/pwm/pwm_loopback/testcase.yaml
Normal file
8
tests/drivers/pwm/pwm_loopback/testcase.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
tests:
|
||||
drivers.pwm.loopback:
|
||||
tags: pwm drivers userspace
|
||||
depends_on: pwm
|
||||
filter: dt_compat_enabled("test,pwm_loopback")
|
||||
harness: ztest
|
||||
harness_config:
|
||||
fixture: pwm_loopback
|
Loading…
Add table
Add a link
Reference in a new issue