1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Verify PWM can work well when configure through nsec,
10  * or cycle.
11  *
12  * @details
13  * - Test Steps
14  *   -# Bind PWM_0 port 0.
15  *   -# Set PWM period and pulse using pwm_set_cycles() or pwm_set().
16  *   -# Use multimeter or other instruments to measure the output
17  *	from PWM_OUT_0.
18  * - Expected Results
19  *   -# The output of PWM_OUT_0 will differ according to the value
20  *	of period and pulse.
21  *	Always on  ->  Period : Pulse (1 : 1)  ->  3.3V
22  *	Half on  ->  Period : Pulse (2 : 1)  ->  1.65V
23  *	Always off  ->  Period : Pulse (1 : 0)  ->  0V
24  */
25 
26 #include <zephyr/device.h>
27 #include <inttypes.h>
28 #include <zephyr/drivers/pwm.h>
29 #include <zephyr/kernel.h>
30 #include <zephyr/ztest.h>
31 
32 #if DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(pwm_0))
33 #define PWM_DEV_NODE DT_ALIAS(pwm_0)
34 #elif DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(pwm_1))
35 #define PWM_DEV_NODE DT_ALIAS(pwm_1)
36 #elif DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(pwm_2))
37 #define PWM_DEV_NODE DT_ALIAS(pwm_2)
38 #elif DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(pwm_3))
39 #define PWM_DEV_NODE DT_ALIAS(pwm_3)
40 
41 #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_pwm)
42 #define PWM_DEV_NODE DT_INST(0, nordic_nrf_pwm)
43 
44 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_pwm)
45 #define PWM_DEV_NODE DT_INST(0, st_stm32_pwm)
46 
47 #elif DT_HAS_COMPAT_STATUS_OKAY(xlnx_xps_timer_1_00_a_pwm)
48 #define PWM_DEV_NODE DT_INST(0, xlnx_xps_timer_1_00_a_pwm)
49 
50 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_ftm_pwm)
51 #define PWM_DEV_NODE DT_INST(0, nxp_ftm_pwm)
52 
53 #elif DT_HAS_COMPAT_STATUS_OKAY(intel_blinky_pwm)
54 #define PWM_DEV_NODE DT_INST(0, intel_blinky_pwm)
55 
56 #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_pwm)
57 #define PWM_DEV_NODE DT_INST(0, renesas_ra_pwm)
58 
59 #else
60 #error "Define a PWM device"
61 #endif
62 
63 #if defined(CONFIG_BOARD_COLIBRI_IMX7D_MCIMX7D_M4) || defined(CONFIG_SOC_MK64F12) ||               \
64 	defined(CONFIG_SOC_MKW41Z4) || defined(CONFIG_SOC_SERIES_ESP32S2) ||                       \
65 	defined(CONFIG_SOC_SERIES_ESP32S3) || defined(CONFIG_SOC_SERIES_ESP32C3)
66 #define DEFAULT_PERIOD_CYCLE 1024
67 #define DEFAULT_PULSE_CYCLE 512
68 #define DEFAULT_PERIOD_NSEC 2000000
69 #define DEFAULT_PULSE_NSEC 500000
70 #elif DT_HAS_COMPAT_STATUS_OKAY(intel_blinky_pwm)
71 #define DEFAULT_PERIOD_CYCLE 32768
72 #define DEFAULT_PULSE_CYCLE 16384
73 #define DEFAULT_PERIOD_NSEC 2000000
74 #define DEFAULT_PULSE_NSEC 500000
75 #else
76 #define DEFAULT_PERIOD_CYCLE 64000
77 #define DEFAULT_PULSE_CYCLE 32000
78 #define DEFAULT_PERIOD_NSEC 2000000
79 #define DEFAULT_PULSE_NSEC 1000000
80 #endif
81 
82 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_fake_pwm)
83 #include <zephyr/fff.h>
84 DEFINE_FFF_GLOBALS;
85 #endif
86 
87 #if defined CONFIG_BOARD_SAM_E70_XPLAINED
88 #define DEFAULT_PWM_PORT 2 /* PWM on EXT2 connector, pin 8 */
89 #elif defined CONFIG_PWM_NRFX
90 #define DEFAULT_PWM_PORT 0
91 #define INVALID_PWM_PORT 9
92 #elif defined CONFIG_BOARD_ADAFRUIT_ITSYBITSY_M4_EXPRESS
93 #define DEFAULT_PWM_PORT 2 /* TCC1/WO[2] on PA18 (D7) */
94 #elif defined CONFIG_BOARD_MIMXRT685_EVK
95 #define DEFAULT_PWM_PORT 7 /* D3 on Arduino connector J27 */
96 #elif defined(CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0_NS) ||                                    \
97 	defined(CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0)
98 #define DEFAULT_PWM_PORT 2 /* D2 on Arduino connector P18 */
99 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_pwm)
100 /* Default port should be adapted per board to fit the channel
101  * associated to the PWM pin. For intsance, for following device,
102  *      pwm1: pwm {
103  *              status = "okay";
104  *              pinctrl-0 = <&tim1_ch3_pe13>;
105  *      };
106  * the following should be used:
107  * #define DEFAULT_PWM_PORT 3
108  */
109 #define DEFAULT_PWM_PORT 1
110 #else
111 #define DEFAULT_PWM_PORT 0
112 #endif
113 
114 #define UNIT_CYCLES	0
115 #define UNIT_NSECS	1
116 
get_pwm_device(void)117 const struct device *get_pwm_device(void)
118 {
119 	return DEVICE_DT_GET(PWM_DEV_NODE);
120 }
121 
test_task(uint32_t port,uint32_t period,uint32_t pulse,uint8_t unit)122 static int test_task(uint32_t port, uint32_t period, uint32_t pulse, uint8_t unit)
123 {
124 	TC_PRINT("[PWM]: %" PRIu8 ", [period]: %" PRIu32 ", [pulse]: %" PRIu32 "\n",
125 		port, period, pulse);
126 
127 	const struct device *pwm_dev = get_pwm_device();
128 
129 	if (!device_is_ready(pwm_dev)) {
130 		TC_PRINT("PWM device is not ready\n");
131 		return TC_FAIL;
132 	}
133 
134 	if (unit == UNIT_CYCLES) {
135 		/* Verify pwm_set_cycles() */
136 		if (pwm_set_cycles(pwm_dev, port, period, pulse, 0)) {
137 			TC_PRINT("Fail to set the period and pulse width\n");
138 			return TC_FAIL;
139 		}
140 	} else { /* unit == UNIT_NSECS */
141 		/* Verify pwm_set() */
142 		if (pwm_set(pwm_dev, port, period, pulse, 0)) {
143 			TC_PRINT("Fail to set the period and pulse width\n");
144 			return TC_FAIL;
145 		}
146 	}
147 
148 	return TC_PASS;
149 }
150 
ZTEST_USER(pwm_basic,test_pwm_nsec)151 ZTEST_USER(pwm_basic, test_pwm_nsec)
152 {
153 	/* Period : Pulse (2000000 : 1000000), unit (nsec). Voltage : 1.65V */
154 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
155 				DEFAULT_PULSE_NSEC, UNIT_NSECS) == TC_PASS, NULL);
156 	k_sleep(K_MSEC(1000));
157 
158 	/* Period : Pulse (2000000 : 2000000), unit (nsec). Voltage : 3.3V */
159 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
160 				DEFAULT_PERIOD_NSEC, UNIT_NSECS) == TC_PASS, NULL);
161 	k_sleep(K_MSEC(1000));
162 
163 	/* Period : Pulse (2000000 : 0), unit (nsec). Voltage : 0V */
164 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
165 				0, UNIT_NSECS) == TC_PASS, NULL);
166 	k_sleep(K_MSEC(1000));
167 }
168 
ZTEST_USER(pwm_basic,test_pwm_cycle)169 ZTEST_USER(pwm_basic, test_pwm_cycle)
170 {
171 	/* Period : Pulse (64000 : 32000), unit (cycle). Voltage : 1.65V */
172 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
173 				DEFAULT_PULSE_CYCLE, UNIT_CYCLES) == TC_PASS, NULL);
174 	k_sleep(K_MSEC(1000));
175 
176 	/* Period : Pulse (64000 : 64000), unit (cycle). Voltage : 3.3V */
177 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
178 				DEFAULT_PERIOD_CYCLE, UNIT_CYCLES) == TC_PASS, NULL);
179 	k_sleep(K_MSEC(1000));
180 
181 	/* Period : Pulse (64000 : 0), unit (cycle). Voltage : 0V */
182 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
183 				0, UNIT_CYCLES) == TC_PASS, NULL);
184 	k_sleep(K_MSEC(1000));
185 }
186 
187 #if defined INVALID_PWM_PORT
ZTEST_USER(pwm_basic,test_pwm_invalid_port)188 ZTEST_USER(pwm_basic, test_pwm_invalid_port)
189 {
190 	const struct device *pwm_dev = get_pwm_device();
191 
192 	TC_PRINT("[PWM]: %" PRIu8 ", [period]: %" PRIu32 ", [pulse]: %" PRIu32 "\n",
193 		INVALID_PWM_PORT, DEFAULT_PERIOD_CYCLE, DEFAULT_PULSE_CYCLE);
194 
195 	zassert_true(device_is_ready(pwm_dev), "PWM device is not ready");
196 
197 	zassert_equal(pwm_set_cycles(pwm_dev, INVALID_PWM_PORT, DEFAULT_PERIOD_CYCLE,
198 				     DEFAULT_PULSE_CYCLE, 0),
199 		      -EINVAL, "Invalid PWM port\n");
200 
201 }
202 #endif
203