Software APIs
dif_pwm_unittest.cc
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <cstring>
8 #include <limits>
9 #include <ostream>
10 
11 #include "gtest/gtest.h"
13 #include "sw/device/lib/base/mock_mmio.h"
16 
17 #include "pwm_regs.h" // Generated.
18 
19 namespace dif_pwm_unittest {
20 namespace {
21 using ::mock_mmio::LeInt;
22 using ::mock_mmio::MmioTest;
23 using ::mock_mmio::MockDevice;
24 
25 class PwmTest : public testing::Test, public MmioTest {
26  protected:
27  dif_pwm_t pwm_ = {.base_addr = dev().region()};
28  dif_pwm_config_t config_ = {
29  .clock_divisor = 2,
30  .beats_per_pulse_cycle = 64,
31  };
32  dif_pwm_channel_config_t channel_config_ = {
33  .duty_cycle_a = 22,
34  .duty_cycle_b = 44,
35  .phase_delay = 0,
36  .mode = kDifPwmModeFirmware,
37  .polarity = kDifPwmPolarityActiveHigh,
38  .blink_parameter_x = 10,
39  .blink_parameter_y = 8,
40  };
41  uint32_t duty_cycle_resolution_ =
43  uint32_t phase_cntr_ticks_per_beat_ =
44  (1U << (16 - duty_cycle_resolution_ - 1));
45 };
46 
47 class ConfigTest : public PwmTest {};
48 
49 TEST_F(ConfigTest, NullArgs) {
50  EXPECT_DIF_BADARG(dif_pwm_configure(nullptr, config_));
51 }
52 
53 TEST_F(ConfigTest, BadArgs) {
54  // Bad clock divisor.
55  config_.clock_divisor = PWM_CFG_CLK_DIV_MASK + 1;
56  config_.beats_per_pulse_cycle = 2;
57  EXPECT_DIF_BADARG(dif_pwm_configure(&pwm_, config_));
58 
59  // Bad duty cycle resolution.
60  config_.clock_divisor = 2;
61  config_.beats_per_pulse_cycle = (1U << (PWM_CFG_DC_RESN_MASK + 1)) + 1;
62  EXPECT_DIF_BADARG(dif_pwm_configure(&pwm_, config_));
63 
64  // Bad duty cycle resolution.
65  config_.clock_divisor = 2;
66  config_.beats_per_pulse_cycle = 1;
67  EXPECT_DIF_BADARG(dif_pwm_configure(&pwm_, config_));
68 }
69 
70 TEST_F(ConfigTest, Locked) {
71  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 0);
72  EXPECT_EQ(dif_pwm_configure(&pwm_, config_), kDifLocked);
73 }
74 
75 TEST_F(ConfigTest, Success) {
76  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
77  EXPECT_READ32(PWM_CFG_REG_OFFSET, 1U << 31);
78  EXPECT_WRITE32(PWM_CFG_REG_OFFSET, 0);
79  EXPECT_WRITE32(PWM_CFG_REG_OFFSET, {{PWM_CFG_CLK_DIV_OFFSET, 2},
80  {PWM_CFG_DC_RESN_OFFSET, 5},
81  {PWM_CFG_CNTR_EN_BIT, 1}})
82  EXPECT_DIF_OK(dif_pwm_configure(&pwm_, config_));
83 }
84 
85 class ConfigChannelTest : public PwmTest {};
86 
87 TEST_F(ConfigChannelTest, NullArgs) {
89  dif_pwm_configure_channel(nullptr, kDifPwmChannel0, channel_config_));
90 }
91 
92 TEST_F(ConfigChannelTest, Locked) {
93  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 0);
94  EXPECT_EQ(dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_),
95  kDifLocked);
96 }
97 
98 TEST_F(ConfigChannelTest, BadChannel) {
99  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
100  EXPECT_READ32(PWM_CFG_REG_OFFSET,
101  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
102  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
104  &pwm_, static_cast<dif_pwm_channel_t>(1U << (PWM_PARAM_N_OUTPUTS + 1)),
105  channel_config_));
106 
107  // Channel enums should be one-hot encoded.
108  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
109  EXPECT_READ32(PWM_CFG_REG_OFFSET,
110  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
111  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
113  &pwm_, static_cast<dif_pwm_channel_t>(3), channel_config_));
114 }
115 
116 TEST_F(ConfigChannelTest, BadDutyCycle) {
117  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
118  EXPECT_READ32(PWM_CFG_REG_OFFSET,
119  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
120 
121  channel_config_.duty_cycle_a = config_.beats_per_pulse_cycle;
123  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
124 
125  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
126  EXPECT_READ32(PWM_CFG_REG_OFFSET,
127  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
128  channel_config_.duty_cycle_a = 24;
129  channel_config_.duty_cycle_b = config_.beats_per_pulse_cycle;
131  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
132 }
133 
134 TEST_F(ConfigChannelTest, BadPhaseDelay) {
135  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
136  EXPECT_READ32(PWM_CFG_REG_OFFSET,
137  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
138 
139  channel_config_.phase_delay = config_.beats_per_pulse_cycle;
141  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
142 }
143 
144 TEST_F(ConfigChannelTest, BadMode) {
145  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
146  EXPECT_READ32(PWM_CFG_REG_OFFSET,
147  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
148  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
149 
150  channel_config_.mode = static_cast<dif_pwm_mode_t>(3);
152  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
153 }
154 
155 TEST_F(ConfigChannelTest, BadPolarity) {
156  channel_config_.polarity = static_cast<dif_pwm_polarity_t>(3);
158  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
159 }
160 
161 TEST_F(ConfigChannelTest, BadBlinkParameterX) {
162  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
163  EXPECT_READ32(PWM_CFG_REG_OFFSET,
164  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
165  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
166 
167  channel_config_.mode = kDifPwmModeHeartbeat;
168  channel_config_.blink_parameter_y = config_.beats_per_pulse_cycle;
170  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
171 }
172 
173 TEST_F(ConfigChannelTest, FirmwareModeSuccess) {
174  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
175  EXPECT_READ32(PWM_CFG_REG_OFFSET,
176  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
177  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
178  EXPECT_WRITE32(PWM_DUTY_CYCLE_0_REG_OFFSET,
179  {{PWM_DUTY_CYCLE_0_A_0_OFFSET,
180  channel_config_.duty_cycle_a * phase_cntr_ticks_per_beat_},
181  {PWM_DUTY_CYCLE_0_B_0_OFFSET,
182  channel_config_.duty_cycle_b * phase_cntr_ticks_per_beat_}});
183  EXPECT_WRITE32(PWM_PWM_PARAM_0_REG_OFFSET,
184  {{PWM_PWM_PARAM_0_PHASE_DELAY_0_OFFSET,
185  channel_config_.phase_delay * phase_cntr_ticks_per_beat_},
186  {PWM_PWM_PARAM_0_HTBT_EN_0_BIT, 0},
187  {PWM_PWM_PARAM_0_BLINK_EN_0_BIT, 0}});
188  EXPECT_WRITE32(PWM_INVERT_REG_OFFSET, 0);
189 
191  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
192 }
193 
194 TEST_F(ConfigChannelTest, BlinkModeSuccess) {
195  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
196  EXPECT_READ32(PWM_CFG_REG_OFFSET,
197  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
198  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
199  EXPECT_WRITE32(PWM_DUTY_CYCLE_0_REG_OFFSET,
200  {{PWM_DUTY_CYCLE_0_A_0_OFFSET,
201  channel_config_.duty_cycle_a * phase_cntr_ticks_per_beat_},
202  {PWM_DUTY_CYCLE_0_B_0_OFFSET,
203  channel_config_.duty_cycle_b * phase_cntr_ticks_per_beat_}});
204  EXPECT_WRITE32(PWM_PWM_PARAM_0_REG_OFFSET,
205  {{PWM_PWM_PARAM_0_PHASE_DELAY_0_OFFSET,
206  channel_config_.phase_delay * phase_cntr_ticks_per_beat_},
207  {PWM_PWM_PARAM_0_HTBT_EN_0_BIT, 0},
208  {PWM_PWM_PARAM_0_BLINK_EN_0_BIT, 1}});
209  EXPECT_WRITE32(
210  PWM_BLINK_PARAM_0_REG_OFFSET,
211  {{PWM_BLINK_PARAM_0_Y_0_OFFSET, channel_config_.blink_parameter_y},
212  {PWM_BLINK_PARAM_0_X_0_OFFSET, channel_config_.blink_parameter_x}});
213  EXPECT_WRITE32(PWM_INVERT_REG_OFFSET, 0);
214 
215  channel_config_.mode = kDifPwmModeBlink;
217  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
218 }
219 
220 TEST_F(ConfigChannelTest, HeartbeatModeSuccess) {
221  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
222  EXPECT_READ32(PWM_CFG_REG_OFFSET,
223  {{PWM_CFG_DC_RESN_OFFSET, duty_cycle_resolution_}});
224  EXPECT_READ32(PWM_INVERT_REG_OFFSET, 0);
225  EXPECT_WRITE32(PWM_DUTY_CYCLE_0_REG_OFFSET,
226  {{PWM_DUTY_CYCLE_0_A_0_OFFSET,
227  channel_config_.duty_cycle_a * phase_cntr_ticks_per_beat_},
228  {PWM_DUTY_CYCLE_0_B_0_OFFSET,
229  channel_config_.duty_cycle_b * phase_cntr_ticks_per_beat_}});
230  EXPECT_WRITE32(PWM_PWM_PARAM_0_REG_OFFSET,
231  {{PWM_PWM_PARAM_0_PHASE_DELAY_0_OFFSET,
232  channel_config_.phase_delay * phase_cntr_ticks_per_beat_},
233  {PWM_PWM_PARAM_0_HTBT_EN_0_BIT, 1},
234  {PWM_PWM_PARAM_0_BLINK_EN_0_BIT, 1}});
235  EXPECT_WRITE32(
236  PWM_BLINK_PARAM_0_REG_OFFSET,
237  {{PWM_BLINK_PARAM_0_Y_0_OFFSET,
238  channel_config_.blink_parameter_y * phase_cntr_ticks_per_beat_},
239  {PWM_BLINK_PARAM_0_X_0_OFFSET, channel_config_.blink_parameter_x}});
240  EXPECT_WRITE32(PWM_INVERT_REG_OFFSET, 0);
241 
242  channel_config_.mode = kDifPwmModeHeartbeat;
244  dif_pwm_configure_channel(&pwm_, kDifPwmChannel0, channel_config_));
245 }
246 
248 
249 TEST_F(PhaseCntrSetEnabledTest, NullArgs) {
251 }
252 
253 TEST_F(PhaseCntrSetEnabledTest, BadArgs) {
255  dif_pwm_phase_cntr_set_enabled(&pwm_, static_cast<dif_toggle_t>(2)));
256 }
257 
258 TEST_F(PhaseCntrSetEnabledTest, Locked) {
259  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 0);
261  kDifLocked);
262 }
263 
264 TEST_F(PhaseCntrSetEnabledTest, Success) {
265  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
266  EXPECT_READ32(PWM_CFG_REG_OFFSET, 0);
267  EXPECT_WRITE32(PWM_CFG_REG_OFFSET, {{PWM_CFG_CNTR_EN_BIT, 1}});
269 }
270 
272 
273 TEST_F(PhaseCntrGetEnabledTest, NullArgs) {
274  dif_toggle_t is_enabled;
275  EXPECT_DIF_BADARG(dif_pwm_phase_cntr_get_enabled(nullptr, &is_enabled));
277 }
278 
279 TEST_F(PhaseCntrGetEnabledTest, Success) {
280  dif_toggle_t is_enabled;
281 
282  EXPECT_READ32(PWM_CFG_REG_OFFSET, {{PWM_CFG_CNTR_EN_BIT, 1}});
283  EXPECT_DIF_OK(dif_pwm_phase_cntr_get_enabled(&pwm_, &is_enabled));
284  EXPECT_EQ(is_enabled, kDifToggleEnabled);
285 
286  EXPECT_READ32(PWM_CFG_REG_OFFSET, {{PWM_CFG_CNTR_EN_BIT, 0}});
287  EXPECT_DIF_OK(dif_pwm_phase_cntr_get_enabled(&pwm_, &is_enabled));
288  EXPECT_EQ(is_enabled, kDifToggleDisabled);
289 }
290 
292 
293 TEST_F(PwmChannelSetEnabledTest, NullArgs) {
295 }
296 
297 TEST_F(PwmChannelSetEnabledTest, BadArgs) {
299  &pwm_, 1U << PWM_PARAM_N_OUTPUTS, kDifToggleEnabled));
301  dif_pwm_channel_set_enabled(&pwm_, 0, static_cast<dif_toggle_t>(2)));
302 }
303 
304 TEST_F(PwmChannelSetEnabledTest, Locked) {
305  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 0);
306  EXPECT_EQ(
307  dif_pwm_channel_set_enabled(&pwm_, kDifPwmChannel0, kDifToggleEnabled),
308  kDifLocked);
309 }
310 
311 TEST_F(PwmChannelSetEnabledTest, Success) {
312  // Set Enabled.
313  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
314  EXPECT_READ32(PWM_PWM_EN_REG_OFFSET, 0xA);
315  EXPECT_WRITE32(PWM_PWM_EN_REG_OFFSET, 0x1E);
317  &pwm_, kDifPwmChannel2 | kDifPwmChannel4, kDifToggleEnabled));
318 
319  // Set Disabled.
320  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, 1);
321  EXPECT_READ32(PWM_PWM_EN_REG_OFFSET, 0x1A);
322  EXPECT_WRITE32(PWM_PWM_EN_REG_OFFSET, 0x2);
324  &pwm_, kDifPwmChannel3 | kDifPwmChannel4, kDifToggleDisabled));
325 }
326 
328 
329 TEST_F(PwmChannelGetEnabledTest, NullArgs) {
330  dif_toggle_t is_enabled;
332  dif_pwm_channel_get_enabled(nullptr, kDifPwmChannel0, &is_enabled));
334  dif_pwm_channel_get_enabled(&pwm_, kDifPwmChannel0, nullptr));
335 }
336 
337 TEST_F(PwmChannelGetEnabledTest, BadArgs) {
338  dif_toggle_t is_enabled;
340  &pwm_, static_cast<dif_pwm_channel_t>(1U << PWM_PARAM_N_OUTPUTS),
341  &is_enabled));
342 }
343 
344 TEST_F(PwmChannelGetEnabledTest, Success) {
345  dif_toggle_t is_enabled;
346 
347  EXPECT_READ32(PWM_PWM_EN_REG_OFFSET, 0xA);
349  dif_pwm_channel_get_enabled(&pwm_, kDifPwmChannel1, &is_enabled));
350  EXPECT_EQ(is_enabled, kDifToggleEnabled);
351 
352  EXPECT_READ32(PWM_PWM_EN_REG_OFFSET, 0xA);
354  dif_pwm_channel_get_enabled(&pwm_, kDifPwmChannel2, &is_enabled));
355  EXPECT_EQ(is_enabled, kDifToggleDisabled);
356 }
357 
358 class PwmLockTest : public PwmTest {};
359 
360 TEST_F(PwmLockTest, NullArgs) { EXPECT_DIF_BADARG(dif_pwm_lock(nullptr)); }
361 
362 TEST_F(PwmLockTest, Success) {
363  EXPECT_WRITE32(PWM_REGWEN_REG_OFFSET, {{PWM_REGWEN_REGWEN_BIT, 0}});
364  EXPECT_DIF_OK(dif_pwm_lock(&pwm_));
365 }
366 
367 class PwmIsLockedTest : public PwmTest {};
368 
369 TEST_F(PwmIsLockedTest, NullArgs) {
370  bool is_locked;
371  EXPECT_DIF_BADARG(dif_pwm_is_locked(nullptr, &is_locked));
372  EXPECT_DIF_BADARG(dif_pwm_is_locked(&pwm_, nullptr));
373 }
374 
375 TEST_F(PwmIsLockedTest, Success) {
376  bool is_locked;
377 
378  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, {{PWM_REGWEN_REGWEN_BIT, 1}});
379  EXPECT_DIF_OK(dif_pwm_is_locked(&pwm_, &is_locked));
380  EXPECT_FALSE(is_locked);
381 
382  EXPECT_READ32(PWM_REGWEN_REG_OFFSET, {{PWM_REGWEN_REGWEN_BIT, 0}});
383  EXPECT_DIF_OK(dif_pwm_is_locked(&pwm_, &is_locked));
384  EXPECT_TRUE(is_locked);
385 }
386 
387 } // namespace
388 } // namespace dif_pwm_unittest