ChibiOS  21.6.0
hal_pwm.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_pwm.c
19  * @brief PWM Driver code.
20  *
21  * @addtogroup PWM
22  * @{
23  */
24 
25 #include "hal.h"
26 
27 #if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__)
28 
29 /*===========================================================================*/
30 /* Driver local definitions. */
31 /*===========================================================================*/
32 
33 /*===========================================================================*/
34 /* Driver exported variables. */
35 /*===========================================================================*/
36 
37 /*===========================================================================*/
38 /* Driver local variables and types. */
39 /*===========================================================================*/
40 
41 /*===========================================================================*/
42 /* Driver local functions. */
43 /*===========================================================================*/
44 
45 /*===========================================================================*/
46 /* Driver exported functions. */
47 /*===========================================================================*/
48 
49 /**
50  * @brief PWM Driver initialization.
51  * @note This function is implicitly invoked by @p halInit(), there is
52  * no need to explicitly initialize the driver.
53  *
54  * @init
55  */
56 void pwmInit(void) {
57 
58  pwm_lld_init();
59 }
60 
61 /**
62  * @brief Initializes the standard part of a @p PWMDriver structure.
63  *
64  * @param[out] pwmp pointer to a @p PWMDriver object
65  *
66  * @init
67  */
68 void pwmObjectInit(PWMDriver *pwmp) {
69 
70  pwmp->state = PWM_STOP;
71  pwmp->config = NULL;
72  pwmp->enabled = 0;
73  pwmp->channels = 0;
74 #if defined(PWM_DRIVER_EXT_INIT_HOOK)
75  PWM_DRIVER_EXT_INIT_HOOK(pwmp);
76 #endif
77 }
78 
79 /**
80  * @brief Configures and activates the PWM peripheral.
81  * @note Starting a driver that is already in the @p PWM_READY state
82  * disables all the active channels.
83  *
84  * @param[in] pwmp pointer to a @p PWMDriver object
85  * @param[in] config pointer to a @p PWMConfig object
86  *
87  * @api
88  */
89 void pwmStart(PWMDriver *pwmp, const PWMConfig *config) {
90 
91  osalDbgCheck((pwmp != NULL) && (config != NULL));
92 
93  osalSysLock();
94  osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY),
95  "invalid state");
96  pwmp->config = config;
97  pwmp->period = config->period;
98  pwm_lld_start(pwmp);
99  pwmp->enabled = 0;
100  pwmp->state = PWM_READY;
101  osalSysUnlock();
102 }
103 
104 /**
105  * @brief Deactivates the PWM peripheral.
106  *
107  * @param[in] pwmp pointer to a @p PWMDriver object
108  *
109  * @api
110  */
111 void pwmStop(PWMDriver *pwmp) {
112 
113  osalDbgCheck(pwmp != NULL);
114 
115  osalSysLock();
116 
117  osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY),
118  "invalid state");
119 
120  pwm_lld_stop(pwmp);
121  pwmp->enabled = 0;
122  pwmp->config = NULL;
123  pwmp->state = PWM_STOP;
124 
125  osalSysUnlock();
126 }
127 
128 /**
129  * @brief Changes the period the PWM peripheral.
130  * @details This function changes the period of a PWM unit that has already
131  * been activated using @p pwmStart().
132  * @pre The PWM unit must have been activated using @p pwmStart().
133  * @post The PWM unit period is changed to the new value.
134  * @note If a period is specified that is shorter than the pulse width
135  * programmed in one of the channels then the behavior is not
136  * guaranteed.
137  *
138  * @param[in] pwmp pointer to a @p PWMDriver object
139  * @param[in] period new cycle time in ticks
140  *
141  * @api
142  */
143 void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period) {
144 
145  osalDbgCheck(pwmp != NULL);
146 
147  osalSysLock();
148  osalDbgAssert(pwmp->state == PWM_READY, "invalid state");
149  pwmChangePeriodI(pwmp, period);
150  osalSysUnlock();
151 }
152 
153 /**
154  * @brief Enables a PWM channel.
155  * @pre The PWM unit must have been activated using @p pwmStart().
156  * @post The channel is active using the specified configuration.
157  * @note Depending on the hardware implementation this function has
158  * effect starting on the next cycle (recommended implementation)
159  * or immediately (fallback implementation).
160  *
161  * @param[in] pwmp pointer to a @p PWMDriver object
162  * @param[in] channel PWM channel identifier (0...channels-1)
163  * @param[in] width PWM pulse width as clock pulses number
164  *
165  * @api
166  */
168  pwmchannel_t channel,
169  pwmcnt_t width) {
170 
171  osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
172 
173  osalSysLock();
174 
175  osalDbgAssert(pwmp->state == PWM_READY, "not ready");
176 
177  pwmEnableChannelI(pwmp, channel, width);
178 
179  osalSysUnlock();
180 }
181 
182 /**
183  * @brief Disables a PWM channel and its notification.
184  * @pre The PWM unit must have been activated using @p pwmStart().
185  * @post The channel is disabled and its output line returned to the
186  * idle state.
187  * @note Depending on the hardware implementation this function has
188  * effect starting on the next cycle (recommended implementation)
189  * or immediately (fallback implementation).
190  *
191  * @param[in] pwmp pointer to a @p PWMDriver object
192  * @param[in] channel PWM channel identifier (0...channels-1)
193  *
194  * @api
195  */
197 
198  osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
199 
200  osalSysLock();
201 
202  osalDbgAssert(pwmp->state == PWM_READY, "not ready");
203 
204  pwmDisableChannelI(pwmp, channel);
205 
206  osalSysUnlock();
207 }
208 
209 /**
210  * @brief Enables the periodic activation edge notification.
211  * @pre The PWM unit must have been activated using @p pwmStart().
212  * @note If the notification is already enabled then the call has no effect.
213  *
214  * @param[in] pwmp pointer to a @p PWMDriver object
215  *
216  * @api
217  */
219 
220  osalDbgCheck(pwmp != NULL);
221 
222  osalSysLock();
223 
224  osalDbgAssert(pwmp->state == PWM_READY, "not ready");
225  osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback");
226 
228 
229  osalSysUnlock();
230 }
231 
232 /**
233  * @brief Disables the periodic activation edge notification.
234  * @pre The PWM unit must have been activated using @p pwmStart().
235  * @note If the notification is already disabled then the call has no effect.
236  *
237  * @param[in] pwmp pointer to a @p PWMDriver object
238  *
239  * @api
240  */
242 
243  osalDbgCheck(pwmp != NULL);
244 
245  osalSysLock();
246 
247  osalDbgAssert(pwmp->state == PWM_READY, "not ready");
248  osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback");
249 
251 
252  osalSysUnlock();
253 }
254 
255 /**
256  * @brief Enables a channel de-activation edge notification.
257  * @pre The PWM unit must have been activated using @p pwmStart().
258  * @pre The channel must have been activated using @p pwmEnableChannel().
259  * @note If the notification is already enabled then the call has no effect.
260  *
261  * @param[in] pwmp pointer to a @p PWMDriver object
262  * @param[in] channel PWM channel identifier (0...channels-1)
263  *
264  * @api
265  */
267 
268  osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
269 
270  osalSysLock();
271 
272  osalDbgAssert(pwmp->state == PWM_READY, "not ready");
273  osalDbgAssert((pwmp->enabled & ((pwmchnmsk_t)1U << (pwmchnmsk_t)channel)) != 0U,
274  "channel not enabled");
275  osalDbgAssert(pwmp->config->channels[channel].callback != NULL,
276  "undefined channel callback");
277 
278  pwmEnableChannelNotificationI(pwmp, channel);
279 
280  osalSysUnlock();
281 }
282 
283 /**
284  * @brief Disables a channel de-activation edge notification.
285  * @pre The PWM unit must have been activated using @p pwmStart().
286  * @pre The channel must have been activated using @p pwmEnableChannel().
287  * @note If the notification is already disabled then the call has no effect.
288  *
289  * @param[in] pwmp pointer to a @p PWMDriver object
290  * @param[in] channel PWM channel identifier (0...channels-1)
291  *
292  * @api
293  */
295 
296  osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
297 
298  osalSysLock();
299 
300  osalDbgAssert(pwmp->state == PWM_READY, "not ready");
301  osalDbgAssert((pwmp->enabled & ((pwmchnmsk_t)1U << (pwmchnmsk_t)channel)) != 0U,
302  "channel not enabled");
303  osalDbgAssert(pwmp->config->channels[channel].callback != NULL,
304  "undefined channel callback");
305 
306  pwmDisableChannelNotificationI(pwmp, channel);
307 
308  osalSysUnlock();
309 }
310 
311 #endif /* HAL_USE_PWM == TRUE */
312 
313 /** @} */
pwmStart
void pwmStart(PWMDriver *pwmp, const PWMConfig *config)
Configures and activates the PWM peripheral.
Definition: hal_pwm.c:89
PWMConfig::callback
pwmcallback_t callback
Periodic callback pointer.
Definition: hal_pwm_lld.h:123
pwmEnableChannelI
#define pwmEnableChannelI(pwmp, channel, width)
Enables a PWM channel.
Definition: hal_pwm.h:191
PWM_READY
@ PWM_READY
Definition: hal_pwm.h:77
pwmObjectInit
void pwmObjectInit(PWMDriver *pwmp)
Initializes the standard part of a PWMDriver structure.
Definition: hal_pwm.c:68
pwmchnmsk_t
uint32_t pwmchnmsk_t
Type of a channels mask.
Definition: hal_pwm_lld.h:78
pwmchannel_t
uint8_t pwmchannel_t
Type of a PWM channel.
Definition: hal_pwm_lld.h:73
PWMConfig::channels
PWMChannelConfig channels[PWM_CHANNELS]
Channels configurations.
Definition: hal_pwm_lld.h:127
hal.h
HAL subsystem header.
pwmDisableChannelNotification
void pwmDisableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel)
Disables a channel de-activation edge notification.
Definition: hal_pwm.c:294
osalSysUnlock
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:611
pwmEnablePeriodicNotificationI
#define pwmEnablePeriodicNotificationI(pwmp)
Enables the periodic activation edge notification.
Definition: hal_pwm.h:236
PWMConfig
Type of a PWM driver configuration structure.
Definition: hal_pwm_lld.h:105
PWMChannelConfig::callback
pwmcallback_t callback
Channel callback pointer.
Definition: hal_pwm_lld.h:98
pwmDisableChannelI
#define pwmDisableChannelI(pwmp, channel)
Disables a PWM channel.
Definition: hal_pwm.h:210
PWMDriver
Structure representing a PWM driver.
Definition: hal_pwm_lld.h:134
PWMDriver::state
pwmstate_t state
Driver state.
Definition: hal_pwm_lld.h:138
pwmDisablePeriodicNotificationI
#define pwmDisablePeriodicNotificationI(pwmp)
Disables the periodic activation edge notification.
Definition: hal_pwm.h:248
pwmEnablePeriodicNotification
void pwmEnablePeriodicNotification(PWMDriver *pwmp)
Enables the periodic activation edge notification.
Definition: hal_pwm.c:218
pwm_lld_stop
void pwm_lld_stop(PWMDriver *pwmp)
Deactivates the PWM peripheral.
Definition: hal_pwm_lld.c:102
pwm_lld_start
void pwm_lld_start(PWMDriver *pwmp)
Configures and activates the PWM peripheral.
Definition: hal_pwm_lld.c:83
PWMDriver::period
pwmcnt_t period
Current PWM period in ticks.
Definition: hal_pwm_lld.h:146
pwm_lld_init
void pwm_lld_init(void)
Low level PWM driver initialization.
Definition: hal_pwm_lld.c:66
pwmChangePeriod
void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period)
Changes the period the PWM peripheral.
Definition: hal_pwm.c:143
osalDbgCheck
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:284
pwmDisableChannelNotificationI
#define pwmDisableChannelNotificationI(pwmp, channel)
Disables a channel de-activation edge notification.
Definition: hal_pwm.h:276
pwmChangePeriodI
#define pwmChangePeriodI(pwmp, value)
Changes the period the PWM peripheral.
Definition: hal_pwm.h:172
PWM_STOP
@ PWM_STOP
Definition: hal_pwm.h:76
osalSysLock
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:601
PWMDriver::config
const PWMConfig * config
Current driver configuration data.
Definition: hal_pwm_lld.h:142
pwmStop
void pwmStop(PWMDriver *pwmp)
Deactivates the PWM peripheral.
Definition: hal_pwm.c:111
pwmDisableChannel
void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel)
Disables a PWM channel and its notification.
Definition: hal_pwm.c:196
osalDbgAssert
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:264
pwmEnableChannelNotificationI
#define pwmEnableChannelNotificationI(pwmp, channel)
Enables a channel de-activation edge notification.
Definition: hal_pwm.h:262
pwmDisablePeriodicNotification
void pwmDisablePeriodicNotification(PWMDriver *pwmp)
Disables the periodic activation edge notification.
Definition: hal_pwm.c:241
pwmInit
void pwmInit(void)
PWM Driver initialization.
Definition: hal_pwm.c:56
pwmEnableChannel
void pwmEnableChannel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width)
Enables a PWM channel.
Definition: hal_pwm.c:167
PWMConfig::period
pwmcnt_t period
PWM period in ticks.
Definition: hal_pwm_lld.h:117
PWMDriver::channels
pwmchannel_t channels
Number of channels in this instance.
Definition: hal_pwm_lld.h:154
pwmcnt_t
uint32_t pwmcnt_t
Type of a PWM counter.
Definition: hal_pwm_lld.h:83
pwmEnableChannelNotification
void pwmEnableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel)
Enables a channel de-activation edge notification.
Definition: hal_pwm.c:266
PWMDriver::enabled
pwmchnmsk_t enabled
Mask of the enabled channels.
Definition: hal_pwm_lld.h:150