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 #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_gpt_pwm)
60 #define PWM_DEV_NODE DT_INST(0, renesas_rz_gpt_pwm)
61 
62 #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_mtu_pwm)
63 #define PWM_DEV_NODE DT_INST(0, renesas_rz_mtu_pwm)
64 
65 #else
66 #error "Define a PWM device"
67 #endif
68 
69 #if defined(CONFIG_BOARD_COLIBRI_IMX7D_MCIMX7D_M4) || defined(CONFIG_SOC_MK64F12) ||               \
70 	defined(CONFIG_SOC_MKW41Z4) || defined(CONFIG_SOC_SERIES_ESP32S2) ||                       \
71 	defined(CONFIG_SOC_SERIES_ESP32S3) || defined(CONFIG_SOC_SERIES_ESP32C3)
72 #define DEFAULT_PERIOD_CYCLE 1024
73 #define DEFAULT_PULSE_CYCLE 512
74 #define DEFAULT_PERIOD_NSEC 2000000
75 #define DEFAULT_PULSE_NSEC 500000
76 #elif DT_HAS_COMPAT_STATUS_OKAY(intel_blinky_pwm)
77 #define DEFAULT_PERIOD_CYCLE 32768
78 #define DEFAULT_PULSE_CYCLE 16384
79 #define DEFAULT_PERIOD_NSEC 2000000
80 #define DEFAULT_PULSE_NSEC 500000
81 #elif defined(CONFIG_SOC_FAMILY_MCXW)
82 #define DEFAULT_PERIOD_CYCLE 64000
83 #define DEFAULT_PULSE_CYCLE 32000
84 #define DEFAULT_PERIOD_NSEC 4000000
85 #define DEFAULT_PULSE_NSEC 2000000
86 #else
87 #define DEFAULT_PERIOD_CYCLE 64000
88 #define DEFAULT_PULSE_CYCLE 32000
89 #define DEFAULT_PERIOD_NSEC 2000000
90 #define DEFAULT_PULSE_NSEC 1000000
91 #endif
92 
93 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_fake_pwm)
94 #include <zephyr/fff.h>
95 DEFINE_FFF_GLOBALS;
96 #endif
97 
98 #if defined CONFIG_BOARD_SAM_E70_XPLAINED
99 #define DEFAULT_PWM_PORT 2 /* PWM on EXT2 connector, pin 8 */
100 #elif defined CONFIG_PWM_NRFX
101 #define DEFAULT_PWM_PORT 0
102 #define INVALID_PWM_PORT 9
103 #elif defined CONFIG_BOARD_ADAFRUIT_ITSYBITSY_M4_EXPRESS
104 #define DEFAULT_PWM_PORT 2 /* TCC1/WO[2] on PA18 (D7) */
105 #elif defined CONFIG_BOARD_MIMXRT685_EVK
106 #define DEFAULT_PWM_PORT 7 /* D3 on Arduino connector J27 */
107 #elif defined(CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0_NS) ||                                    \
108 	defined(CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0)
109 #define DEFAULT_PWM_PORT 2 /* D2 on Arduino connector P18 */
110 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_pwm)
111 /* Default port should be adapted per board to fit the channel
112  * associated to the PWM pin. For intsance, for following device,
113  *      pwm1: pwm {
114  *              status = "okay";
115  *              pinctrl-0 = <&tim1_ch3_pe13>;
116  *      };
117  * the following should be used:
118  * #define DEFAULT_PWM_PORT 3
119  */
120 #define DEFAULT_PWM_PORT 1
121 #else
122 #define DEFAULT_PWM_PORT 0
123 #endif
124 
125 #define UNIT_CYCLES	0
126 #define UNIT_NSECS	1
127 
get_pwm_device(void)128 const struct device *get_pwm_device(void)
129 {
130 	return DEVICE_DT_GET(PWM_DEV_NODE);
131 }
132 
test_task(uint32_t port,uint32_t period,uint32_t pulse,uint8_t unit)133 static int test_task(uint32_t port, uint32_t period, uint32_t pulse, uint8_t unit)
134 {
135 	TC_PRINT("[PWM]: %" PRIu8 ", [period]: %" PRIu32 ", [pulse]: %" PRIu32 "\n",
136 		port, period, pulse);
137 
138 	const struct device *pwm_dev = get_pwm_device();
139 
140 	if (!device_is_ready(pwm_dev)) {
141 		TC_PRINT("PWM device is not ready\n");
142 		return TC_FAIL;
143 	}
144 
145 	if (unit == UNIT_CYCLES) {
146 		/* Verify pwm_set_cycles() */
147 		if (pwm_set_cycles(pwm_dev, port, period, pulse, 0)) {
148 			TC_PRINT("Fail to set the period and pulse width\n");
149 			return TC_FAIL;
150 		}
151 	} else { /* unit == UNIT_NSECS */
152 		/* Verify pwm_set() */
153 		if (pwm_set(pwm_dev, port, period, pulse, 0)) {
154 			TC_PRINT("Fail to set the period and pulse width\n");
155 			return TC_FAIL;
156 		}
157 	}
158 
159 	return TC_PASS;
160 }
161 
ZTEST_USER(pwm_basic,test_pwm_nsec)162 ZTEST_USER(pwm_basic, test_pwm_nsec)
163 {
164 	/* Period : Pulse (2000000 : 1000000), unit (nsec). Voltage : 1.65V */
165 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
166 				DEFAULT_PULSE_NSEC, UNIT_NSECS) == TC_PASS);
167 	k_sleep(K_MSEC(1000));
168 
169 	/* Period : Pulse (2000000 : 2000000), unit (nsec). Voltage : 3.3V */
170 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
171 				DEFAULT_PERIOD_NSEC, UNIT_NSECS) == TC_PASS);
172 	k_sleep(K_MSEC(1000));
173 
174 	/* Period : Pulse (2000000 : 0), unit (nsec). Voltage : 0V */
175 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
176 				0, UNIT_NSECS) == TC_PASS);
177 	k_sleep(K_MSEC(1000));
178 }
179 
ZTEST_USER(pwm_basic,test_pwm_cycle)180 ZTEST_USER(pwm_basic, test_pwm_cycle)
181 {
182 	/* Period : Pulse (64000 : 32000), unit (cycle). Voltage : 1.65V */
183 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
184 				DEFAULT_PULSE_CYCLE, UNIT_CYCLES) == TC_PASS);
185 	k_sleep(K_MSEC(1000));
186 
187 	/* Period : Pulse (64000 : 64000), unit (cycle). Voltage : 3.3V */
188 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
189 				DEFAULT_PERIOD_CYCLE, UNIT_CYCLES) == TC_PASS);
190 	k_sleep(K_MSEC(1000));
191 
192 	/* Period : Pulse (64000 : 0), unit (cycle). Voltage : 0V */
193 	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
194 				0, UNIT_CYCLES) == TC_PASS);
195 	k_sleep(K_MSEC(1000));
196 }
197 
198 #if defined INVALID_PWM_PORT
ZTEST_USER(pwm_basic,test_pwm_invalid_port)199 ZTEST_USER(pwm_basic, test_pwm_invalid_port)
200 {
201 	const struct device *pwm_dev = get_pwm_device();
202 
203 	TC_PRINT("[PWM]: %" PRIu8 ", [period]: %" PRIu32 ", [pulse]: %" PRIu32 "\n",
204 		INVALID_PWM_PORT, DEFAULT_PERIOD_CYCLE, DEFAULT_PULSE_CYCLE);
205 
206 	zassert_true(device_is_ready(pwm_dev), "PWM device is not ready");
207 
208 	zassert_equal(pwm_set_cycles(pwm_dev, INVALID_PWM_PORT, DEFAULT_PERIOD_CYCLE,
209 				     DEFAULT_PULSE_CYCLE, 0),
210 		      -EINVAL, "Invalid PWM port\n");
211 
212 }
213 #endif
214