Software APIs
dif_pwm.h
Go to the documentation of this file.
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
5#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_PWM_H_
6#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_PWM_H_
7
8/**
9 * @file
10 * @brief <a href="/book/hw/ip/pwm/">PWM</a> Device Interface Functions
11 *
12 * The PWM block contains a 16-bit "phase counter" that controls each channel's
13 * output signal. The "phase counter" acts as a point of reference for a single
14 * PWM "pulse cycle", that is further broken into "beats", depending on the
15 * `beats_per_cycle` parameter. Specifically, a "pulse cycle" may contain [2,
16 * 2^16] "beats". Within a "pulse cycle", users can configure the duty cycle in
17 * number of "beats". Additionally, the duration of a single "beat", is computed
18 * by dividing the core clock frequency by `clock_divisor + 1`.
19 *
20 * PWM "pulse cycle" defined by 16-bit phase counter
21 * ___________________________________________________________
22 * | |
23 * v v
24 * |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| ... |-|-|-|-|
25 *
26 * |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| ... |-|-|-|-|
27 * min beat size = 1 phase counter tick --> 2^16 "beats" / "pulse cycle"
28 *
29 * |---------------------------------------------- ... | ... --|
30 * max beat size = 2^15 phase counter ticks --> 2 "beats" / "pulse cycle"
31 */
32
33#include <stdint.h>
34
36
37#ifdef __cplusplus
38extern "C" {
39#endif // __cplusplus
40
41/**
42 * A PWM channel.
43 *
44 * Channels are numbered 0 to N-1, where N is the number of channels.
45 */
46typedef size_t dif_pwm_channel_t;
47
48/**
49 * Runtime configuration for PWM.
50 *
51 * This struct describes runtime configuration for one-time configuration of the
52 * PWM "pulse cycle" and "beat" durations that impact all PWM channels.
53 */
54typedef struct dif_pwm_config {
55 /**
56 * The core clock frequency divisor that determines the period of a single
57 * "beat" within a PWM "pulse cycle".
58 *
59 * Valid range: [0, 2^26)
60 *
61 * A value of zero, configures the "beat" period to the core clock period.
62 */
63 uint32_t clock_divisor;
64 /**
65 * The total number of "beats" in a "pulse cycle", including both "on" and
66 * "off" beats in a "pulse cycle".
67 *
68 * Valid range: [2, 2^16]
69 *
70 * Note: while any value in the range is acceptable, values will be rounded
71 * down to closest power-of-two.
72 *
73 * A "beat" represents a unit of time of the PWM output signal. Higher values
74 * provide higher duty cycle resolutions, at the expense of longer "pulse
75 * cycles", while lower values provide shorter "pulse cycles", at the expense
76 * of lower duty cycle resolutions (since duty cycles are configured in
77 * "beats" / "pulse cycle").
78 */
81
82/**
83 * A PWM channel mode.
84 */
85typedef enum dif_pwm_mode {
86 /**
87 * The PWM duty cycle is set by the firmware and remains constant.
88 */
90 /**
91 * The PWM duty cycle linearly sweeps between both primary and secondary
92 * firmware-configured values, based on a firmware-configured step size.
93 */
95 /**
96 * The PWM duty cycle alternates between both primary and secondary
97 * firmware-configured values, based on two firmware-configured durations.
98 */
101
102/**
103 * A PWM channel polarity.
104 */
105typedef enum dif_pwm_polarity {
106 /**
107 * A PWM signal is active-high.
108 */
110 /**
111 * A PWM signal is active-low.
112 */
115
116/**
117 * Runtime configuration for a specific PWM channel.
118 *
119 * This struct describes runtime configuration for one-time configuration of a
120 * specific PWM channel.
121 */
123 /**
124 * Primary duty cycle, in number of "beats" / "pulse cycle".
125 *
126 * Valid range: [0, beats_per_pulse_cycle)
127 *
128 * Note: the raw value written to the `A_*` bitfield in each PWM channel's
129 * `DUTY_CYCLE_*` CSR is in units of "phase counter ticks", not "beats".
130 * However, the hardware only takes into account the first `DC_RESN` + 1
131 * MSBs of the raw duty cycle value to determine the number of "beats"
132 * for a given duty cycle. To make this configuration easier, the
133 * software manages the conversion from "beats_per_cycle" to
134 * "phase_counter_ticks" under the hood.
135 */
136 uint16_t duty_cycle_a;
137 /**
138 * Secondary duty cycle, in number of "beats" / "pulse cycle", that is only
139 * relevant in heartbeat and blink modes.
140 *
141 * Valid range: [0, beats_per_pulse_cycle)
142 *
143 * Note: above notes for `duty_cycle_a` apply here too.
144 */
145 uint16_t duty_cycle_b;
146 /**
147 * Phase delay at the beginning of a "pulse cycle" to delay the active
148 * duty cycle "beats" for, in number of "beats".
149 *
150 * Valid range: [0, beats_per_pulse_cycle)
151 */
152 uint16_t phase_delay;
153 /**
154 * The operation mode to configure the channel in, see `dif_pwm_mode_t`.
155 */
157 /**
158 * The polarity to configure the channel in, see `dif_pwm_polarity_t`.
159 */
161 /**
162 * One of two blink parameters that only impact the "Heartbeat" and "Blink"
163 * operation modes.
164 *
165 * The meaning of this parameter is different based on the operation mode:
166 * - Heartbeat mode: determines the number of "pulse cycles" between
167 * increments/decrements to the duty cycle.
168 *
169 * - Blink mode: determines the number of "pulse cycles" to pulse at duty
170 * cycle A, before switching to duty cycle B.
171 */
173 /**
174 * One of two blink parameters that only impact the "Heartbeat" and "Blink"
175 * operation modes.
176 *
177 * The meaning of this parameter is different based on the operation mode:
178 * - Heartbeat mode: determines the increment/decrement amount in number
179 * of duty cycle "beats".
180 *
181 * - Blink mode: determines the number of "pulse cycles" to pulse at duty
182 * cycle B, before switching to duty cycle A.
183 *
184 * Note: the raw value written to the `blink_parameter_x` bitfield in each PWM
185 * channel's `BLINK_PARAM_*` CSR is in units of "phase counter ticks", not
186 * "beats". However, for ease of configuration, the software manages this
187 * conversion under the hood.
188 */
191
192/**
193 * Configures "phase cycle" and "beat" durations of all PWM channels.
194 *
195 * Since changes to `CLK_DIV` and `DC_RESN` are only allowed when the PWM is
196 * disabled, this function has the side effect of temporarily disabling all PWM
197 * channels while configurations are updated, before restoring the original
198 * enablement state.
199 *
200 * This function should only need to be called once for the lifetime of
201 * `handle`.
202 *
203 * @param pwm A PWM handle.
204 * @param config Runtime configuration parameters.
205 * @return The result of the operation.
206 */
209
210/**
211 * Configures a single PWM channel.
212 *
213 * This function should only need to be called once for each PWM channel that
214 * will be used.
215 *
216 * @param pwm A PWM handle.
217 * @param channel A PWM channel to configure.
218 * @param config Runtime configuration parameters for the channel.
219 * @return The result of the operation.
220 */
223 dif_pwm_channel_t channel,
225
226/**
227 * Sets the enablement state of the PWM phase counter, which controls the
228 * enablement of all PWM channels.
229 *
230 * @param pwm A PWM handle.
231 * @param enabled The enablement state to configure the PWM phase counter in.
232 * @return The result of the operation.
233 */
236 dif_toggle_t enabled);
237
238/**
239 * Gets the enablement state of the PWM phase counter, which controls the
240 * enablement of all PWM channels.
241 *
242 * @param pwm A PWM handle.
243 * @param[out] is_enabled The enablement state of the PWM phase counter.
244 * @return The result of the operation.
245 */
248 dif_toggle_t *is_enabled);
249
250/**
251 * Sets the enablement states of one or more PWM channels.
252 *
253 * @param pwm A PWM handle.
254 * @param channels The channels to enable (bitmask, the i-th bit corresponds to
255 * the i-th channel).
256 * @param enabled The enablement state to set.
257 * @return The result of the operation.
258 */
261 uint32_t channels,
262 dif_toggle_t enabled);
263
264/**
265 * Gets the enablement state of one PWM channel.
266 *
267 * @param pwm A PWM handle.
268 * @param channel The PWM channel to get the enablement state of.
269 * @param[out] is_enabled The enablement state of the PWM channel.
270 * @return The result of the operation.
271 */
274 dif_pwm_channel_t channel,
275 dif_toggle_t *is_enabled);
276
277/**
278 * Locks PWM configurations.
279 *
280 * This function is reentrant: calling it while locked will have no effect and
281 * return `kDifOk`.
282 *
283 * @param pwm A PWM handle.
284 * @return The result of the operation.
285 */
288
289/**
290 * Checks whether PWM configurations are locked.
291 *
292 * @param pwm A PWM handle.
293 * @param[out] is_locked Out-param for the locked state.
294 * @return The result of the operation.
295 */
297dif_result_t dif_pwm_is_locked(const dif_pwm_t *pwm, bool *is_locked);
298
299#ifdef __cplusplus
300} // extern "C"
301#endif // __cplusplus
302
303#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_PWM_H_