This is an automated email from the ASF dual-hosted git repository.

janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git


The following commit(s) were added to refs/heads/master by this push:
     new eb7d153cf test/mtest: PWM duty cycle verification test using GPIO 
loopback
eb7d153cf is described below

commit eb7d153cf10368d1c41d0ae36c93113150dd84f6
Author: Wiktor Kwiatkowski <[email protected]>
AuthorDate: Fri Jan 30 16:19:47 2026 +0100

    test/mtest: PWM duty cycle verification test using GPIO loopback
    
    Add test that verifies PWM duty cycle accuracy by sampling the
    output pin via GPIO reads. The test uses a timer to sample GPIO state
    and calculates measured duty cycle from high versus total samples.
    
    Each test configures PWM duty, collects samples via timer callback,
    and validates measured duty falls within tolerance.
    
    Test requires physical loopback between PWM output and GPIO input pin.
---
 test/mtest/mtest_pwm/include/mtest_pwm/mtest_pwm.h |  69 ++++++++++++
 test/mtest/mtest_pwm/pkg.yml                       |  32 ++++++
 test/mtest/mtest_pwm/src/main.c                    | 120 +++++++++++++++++++++
 test/mtest/mtest_pwm/src/pwm_test_cases.c          |  90 ++++++++++++++++
 test/mtest/mtest_pwm/syscfg.yml                    |  96 +++++++++++++++++
 5 files changed, 407 insertions(+)

diff --git a/test/mtest/mtest_pwm/include/mtest_pwm/mtest_pwm.h 
b/test/mtest/mtest_pwm/include/mtest_pwm/mtest_pwm.h
new file mode 100644
index 000000000..dfd652941
--- /dev/null
+++ b/test/mtest/mtest_pwm/include/mtest_pwm/mtest_pwm.h
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef MTEST_PWM_H
+#define MTEST_PWM_H
+#include "mtest/mtest.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PWM_TEST_DEV MYNEWT_VAL(PWM_TEST_DEV_NAME)
+
+#define TIMER_FREQ_HZ  MYNEWT_VAL(OS_CPUTIME_FREQ)
+#define SAMPLE_FREQ_HZ 1000
+#define PWM_FREQ_HZ    200
+
+#define TIMER_TICKS    (TIMER_FREQ_HZ / SAMPLE_FREQ_HZ)
+#define MEASURE_TIME_S 1
+#define WINDOW_SIZE    (SAMPLE_FREQ_HZ * MEASURE_TIME_S)
+
+#if MYNEWT_VAL(BSP_IS_NUCLEO)
+#define PWM_TEST_CH_CFG_PIN                                                   \
+    MCU_AFIO_GPIO(MYNEWT_VAL(PWM_TEST_OUT_PIN), 
MYNEWT_VAL(PWM_TEST_OUT_PIN_AF))
+#else
+#define PWM_TEST_CH_CFG_PIN MYNEWT_VAL(PWM_TEST_OUT_PIN)
+#endif
+#define PWM_TEST_CH_NUM     MYNEWT_VAL(PWM_TEST_CHANNEL)
+#define PWM_TEST_CH_CFG_INV MYNEWT_VAL(PWM_TEST_INVERT_OUTPUT)
+
+struct pwm_test_ctx {
+    struct pwm_dev *pwm;
+    struct os_sem sem;
+    struct hal_timer timer;
+
+    int sample_cnt;
+    int high_cnt;
+};
+
+extern struct pwm_test_ctx test_ctx;
+
+MTEST_CASE_DECL(pwm_test_case_1);
+MTEST_CASE_DECL(pwm_test_case_2);
+MTEST_CASE_DECL(pwm_test_case_3);
+MTEST_CASE_DECL(pwm_test_case_4);
+MTEST_CASE_DECL(pwm_test_case_5);
+MTEST_CASE_DECL(pwm_test_case_6);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/mtest/mtest_pwm/pkg.yml b/test/mtest/mtest_pwm/pkg.yml
new file mode 100644
index 000000000..658dc7c14
--- /dev/null
+++ b/test/mtest/mtest_pwm/pkg.yml
@@ -0,0 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: test/mtest/mtest_pwm
+pkg.description: PWM duty cycle verification via GPIO loopback
+pkg.author: "Apache Mynewt <[email protected]>"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+pkg.type: app
+pkg.deps:
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/sys/log/"
+    - "@apache-mynewt-core/hw/drivers/pwm"
+    - "@apache-mynewt-core/test/mtest/mtest"
+    - "@apache-mynewt-core/hw/drivers/pwm"
diff --git a/test/mtest/mtest_pwm/src/main.c b/test/mtest/mtest_pwm/src/main.c
new file mode 100644
index 000000000..efbd0d334
--- /dev/null
+++ b/test/mtest/mtest_pwm/src/main.c
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "sysinit/sysinit.h"
+#include "bsp/bsp.h"
+#include "pwm/pwm.h"
+#include "hal/hal_gpio.h"
+#include "mtest_pwm/mtest_pwm.h"
+
+struct pwm_test_ctx test_ctx;
+
+void
+pwm_init(void)
+{
+    struct pwm_chan_cfg chan_conf;
+    int rc;
+
+    chan_conf = (struct pwm_chan_cfg){ .pin = PWM_TEST_CH_CFG_PIN,
+                                       .inverted = PWM_TEST_CH_CFG_INV,
+                                       .data = NULL };
+
+    test_ctx.pwm =
+        (struct pwm_dev *)os_dev_open(PWM_TEST_DEV, OS_TIMEOUT_NEVER, NULL);
+    MTEST_INIT_ASSERT(test_ctx.pwm != NULL, "device %s not available\n", 
PWM_TEST_DEV);
+    rc = pwm_set_frequency(test_ctx.pwm, PWM_FREQ_HZ);
+    MTEST_INIT_ASSERT(rc > 0, "set frequency for pwm clock failed");
+
+    rc = pwm_configure_channel(test_ctx.pwm, PWM_TEST_CH_NUM, &chan_conf);
+    MTEST_INIT_ASSERT(rc == 0, "channel configuration failed");
+
+    rc = pwm_enable(test_ctx.pwm);
+    MTEST_INIT_ASSERT(rc == 0, "PWM enable");
+}
+
+void
+timer_cb(void *arg)
+{
+    if (test_ctx.sample_cnt < WINDOW_SIZE) {
+        test_ctx.sample_cnt++;
+        if (hal_gpio_read(MYNEWT_VAL(PWM_TEST_READ_PIN))) {
+            test_ctx.high_cnt++;
+        }
+
+        if (test_ctx.sample_cnt == WINDOW_SIZE) {
+            os_cputime_timer_stop(&test_ctx.timer);
+            os_sem_release(&test_ctx.sem);
+        } else {
+            os_cputime_timer_relative(&test_ctx.timer, TIMER_TICKS);
+        }
+    }
+}
+
+MTEST_INIT(pwm_test)
+{
+    int rc;
+    os_error_t err;
+
+    rc = hal_gpio_init_in(MYNEWT_VAL(PWM_TEST_READ_PIN), HAL_GPIO_PULL_DOWN);
+    MTEST_INIT_ASSERT(rc == 0, "pin configuration failed");
+
+    err = os_sem_init(&test_ctx.sem, 0);
+    MTEST_INIT_ASSERT(err == 0, "semaphore init failed");
+
+    os_cputime_timer_init(&test_ctx.timer, timer_cb, NULL);
+
+    pwm_init();
+}
+
+MTEST_CLEANUP(pwm_test)
+{
+    int rc;
+
+    rc = pwm_disable(test_ctx.pwm);
+    MTEST_CLEANUP_ASSERT(rc == 0, "disable PWM failed");
+
+    os_cputime_timer_stop(&test_ctx.timer);
+
+    rc = os_dev_close((struct os_dev *)test_ctx.pwm);
+    MTEST_CLEANUP_ASSERT(rc == 0, "dev close failed");
+}
+
+MTEST_SUITE(pwm_test)
+{
+    MTEST_RUN_INIT(pwm_test);
+    pwm_test_case_1();
+    pwm_test_case_2();
+    pwm_test_case_3();
+    pwm_test_case_4();
+    pwm_test_case_5();
+    pwm_test_case_6();
+    MTEST_RUN_CLEANUP(pwm_test);
+}
+
+int
+mynewt_main(int argc, char **argv)
+{
+    sysinit();
+
+    pwm_test();
+
+    while (1) {
+        os_time_delay(OS_TICKS_PER_SEC);
+    }
+}
diff --git a/test/mtest/mtest_pwm/src/pwm_test_cases.c 
b/test/mtest/mtest_pwm/src/pwm_test_cases.c
new file mode 100644
index 000000000..d8b6e5386
--- /dev/null
+++ b/test/mtest/mtest_pwm/src/pwm_test_cases.c
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "pwm/pwm.h"
+#include "mtest_pwm/mtest_pwm.h"
+
+void
+test_pwm_duty_cycle(int duty_percent)
+{
+    int top;
+    int duty_val;
+    int rc;
+    int measured_duty;
+    int diff;
+    test_ctx.sample_cnt = 0;
+    test_ctx.high_cnt = 0;
+
+    top = pwm_get_top_value(test_ctx.pwm);
+    MTEST_CASE_ASSERT(top > 0, "PWM get top value failed");
+
+    duty_val = top * duty_percent / 100;
+    rc = pwm_set_duty_cycle(test_ctx.pwm, PWM_TEST_CH_NUM, duty_val);
+    MTEST_CASE_ASSERT(rc == 0, "set duty cycle %u%% (value=%d) failed",
+                      duty_percent, duty_val);
+
+    rc = os_cputime_timer_relative(&test_ctx.timer, TIMER_TICKS);
+    MTEST_CASE_ASSERT(rc == 0, "timer start failed");
+
+    rc = os_sem_pend(&test_ctx.sem, OS_TICKS_PER_SEC * 10);
+    MTEST_CASE_ASSERT(rc == 0, "measurement timeout for duty %d%%", 
duty_percent);
+
+    MTEST_CASE_ASSERT(test_ctx.sample_cnt > 0, "no samples collected");
+
+    measured_duty = test_ctx.high_cnt * 100 / test_ctx.sample_cnt;
+    diff = measured_duty - duty_percent;
+    if (diff < 0) {
+        diff = -diff;
+    }
+
+    MTEST_CASE_ASSERT(
+        diff < MYNEWT_VAL(PWM_TEST_TOLERANCE),
+        "duty tolerance exceeded: expected %d%%, measured %d%%, diff %d%% (max 
%d%%)",
+        duty_percent, measured_duty, diff, MYNEWT_VAL(PWM_TEST_TOLERANCE));
+}
+
+MTEST_CASE(pwm_test_case_1)
+{
+    test_pwm_duty_cycle(0);
+}
+
+MTEST_CASE(pwm_test_case_2)
+{
+    test_pwm_duty_cycle(20);
+}
+
+MTEST_CASE(pwm_test_case_3)
+{
+    test_pwm_duty_cycle(40);
+}
+
+MTEST_CASE(pwm_test_case_4)
+{
+    test_pwm_duty_cycle(60);
+}
+
+MTEST_CASE(pwm_test_case_5)
+{
+    test_pwm_duty_cycle(80);
+}
+
+MTEST_CASE(pwm_test_case_6)
+{
+    test_pwm_duty_cycle(100);
+}
diff --git a/test/mtest/mtest_pwm/syscfg.yml b/test/mtest/mtest_pwm/syscfg.yml
new file mode 100644
index 000000000..72a44d9e1
--- /dev/null
+++ b/test/mtest/mtest_pwm/syscfg.yml
@@ -0,0 +1,96 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+syscfg.defs:
+    PWM_TEST_READ_PIN:
+      description: 'Pin used to read the incoming PWM signal.'
+      value: ARDUINO_PIN_D7
+
+    PWM_TEST_OUT_PIN:
+      description: 'Pin used to output the generated PWM signal.'
+      value: LED_BLINK_PIN
+
+    PWM_TEST_OUT_PIN_AF:
+      description: 'Alternate Function number for the output pin (STM32 only).'
+      value: 0
+
+    PWM_TEST_CHANNEL:
+      description: 'Hardware timer channel used for PWM generation.'
+      value: 0
+
+    PWM_TEST_DEV_NAME:
+      description: 'Name of the OS device for PWM.'
+      value: '"pwm0"'
+
+    PWM_TEST_INVERT_OUTPUT:
+      description: 'Set to 1 to invert the output PWM signal.'
+      value: 0
+
+    PWM_TEST_TOLERANCE:
+      description: 'Acceptable error for PWM readings (in %).'
+      value: 5
+
+    BSP_IS_NUCLEO:
+      description: 'Set to 1 if the current board is an STM32 Nucleo.'
+      value: 0
+
+syscfg.vals:
+    PWM_0: 1
+
+syscfg.vals.BSP_nucleo_f411re:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_DEV_NAME: '"pwm1"'
+    PWM_1: 1
+    PWM_0: 0
+    PWM_TEST_OUT_PIN_AF: 1
+
+syscfg.vals.BSP_nucleo_f767zi:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_OUT_PIN_AF: 2
+    PWM_TEST_CHANNEL: 2
+
+syscfg.vals.BSP_nucleo_g0b1re:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_OUT_PIN_AF: 2
+
+syscfg.vals.BSP_nucleo_g491re:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_OUT_PIN: ARDUINO_PIN_D5
+    PWM_TEST_OUT_PIN_AF: 2
+    PWM_TEST_READ_PIN: ARDUINO_PIN_D6
+
+syscfg.vals.BSP_nucleo_h723zg:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_OUT_PIN_AF: 2
+    PWM_TEST_CHANNEL: 2
+
+syscfg.vals.BSP_nucleo_h753zi:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_OUT_PIN_AF: 2
+    PWM_TEST_CHANNEL: 2
+
+syscfg.vals.BSP_nucleo_u575zi_q:
+    BSP_IS_NUCLEO: 1
+    PWM_TEST_OUT_PIN: ARDUINO_PIN_D11
+    PWM_TEST_OUT_PIN_AF: 2
+    PWM_TEST_CHANNEL: 1
+    PWM_TEST_READ_PIN: ARDUINO_PIN_D7
+
+syscfg.vals.BSP_dialog_da1469x_dk_pro:
+    TIMER_0: 0
+    TIMER_1: 1
+    OS_CPUTIME_TIMER_NUM: 1

Reply via email to