2 * Copyright (c) 2015-2016, Texas Instruments Incorporated
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 /** ============================================================================
34 * @brief PWM driver interface
36 * To use the PWM driver, ensure that the correct driver library for your
37 * device is linked in and include this header file as follows:
39 * #include <ti/drivers/PWM.h>
42 * This module serves as the main interface for applications. Its purpose
43 * is to redirect the PWM APIs to specific driver implementations
44 * which are specified using a pointer to a #PWM_FxnTable.
47 * The PWM driver in TI-RTOS facilitates the generation of Pulse Width
48 * Modulated signals via simple and portable APIs. PWM instances must be
49 * opened by calling PWM_open() while passing in a PWM index and a parameters
52 * The driver APIs serve as an interface to a typical TI-RTOS application.
53 * The specific peripheral implementations are responsible for creating all OS
54 * specific primitives to allow for thread-safe operation.
56 * When a PWM instance is opened, the period, duty cycle and idle level are
57 * configured and the PWM is stopped (waveforms not generated until PWM_start()
58 * is called). The maximum period and duty supported is device dependent;
59 * refer to the implementation specific documentation for values.
61 * PWM outputs are active-high, meaning the duty will control the duration of
62 * high output on the pin (at 0% duty, the output is always low, at 100% duty,
63 * the output is always high).
69 * PWM_Params pwmParams;
71 * // Initialize the PWM driver.
74 * // Initialize the PWM parameters
75 * PWM_Params_init(&pwmParams);
76 * pwmParams.idleLevel = PWM_IDLE_LOW; // Output low when PWM is not running
77 * pwmParams.period.unit = PWM_PERIOD_HZ; // Period is in Hz
78 * pwmParams.period.value = 1e6; // 1MHz
79 * pwmParams.duty.unit = PWM_DUTY_FRACTION; // Duty is in fractional percentage
80 * pwmParams.duty.value = 0; // 0% initial duty cycle
82 * // Open the PWM instance
83 * pwm = PWM_open(Board_PWM0, &pwmParams);
86 * // PWM_open() failed
90 * PWM_start(handle); // start PWM with 0% duty cycle
93 * (PWM_DUTY_FRACTION_MAX / 2)); // set duty cycle to 50%
96 * Details for the example code above are described in the following
99 * ### PWM Driver Configuration #
101 * In order to use the PWM APIs, the application is required
102 * to provide device-specific PWM configuration in the Board.c file.
103 * The PWM driver interface defines a configuration data structure:
106 * typedef struct PWM_Config_ {
107 * PWM_FxnTable const *fxnTablePtr;
109 * void const *hwAttrs;
113 * The application must declare an array of PWM_Config elements, named
114 * PWM_config[]. Each element of PWM_config[] is populated with
115 * pointers to a device specific PWM driver implementation's function
116 * table, driver object, and hardware attributes. The hardware attributes
117 * define properties such as which pin will be driven, and which timer peripheral
118 * will be used. Each element in PWM_config[] corresponds to
119 * a PWM instance, and none of the elements should have NULL pointers.
121 * Additionally, the PWM driver interface defines a global integer variable
122 * 'PWM_count' which is initialized to the number of PWM instances the
123 * application has defined in the PWM_Config array.
125 * You will need to check the device-specific PWM driver implementation's
126 * header file for example configuration. Please also refer to the
127 * Board.c file of any of your examples to see the PWM configuration.
129 * ### Initializing the PWM Driver #
131 * PWM_init() must be called before any other PWM APIs. This function
132 * calls the device implementation's PWM initialization function, for each
133 * element of PWM_config[].
135 * ### Opening the PWM Driver #
137 * Opening a PWM requires four steps:
138 * 1. Create and initialize a PWM_Params structure.
139 * 2. Fill in the desired parameters.
140 * 3. Call PWM_open(), passing the index of the PWM in the PWM_config
141 * structure, and the address of the PWM_Params structure. The
142 * PWM instance is specified by the index in the PWM_config structure.
143 * 4. Check that the PWM handle returned by PWM_open() is non-NULL,
144 * and save it. The handle will be used to read and write to the
145 * PWM you just opened.
147 * Only one PWM index can be used at a time; calling PWM_open() a second
148 * time with the same index previously passed to PWM_open() will result in
149 * an error. You can, though, re-use the index if the instance is closed
151 * In the example code, Board_PWM0 is passed to PWM_open(). This macro
152 * is defined in the example's Board.h file.
154 * ### Modes of Operation #
156 * A PWM instance can be configured to interpret the period as one of three
158 * - #PWM_PERIOD_US: The period is in microseconds.
159 * - #PWM_PERIOD_HZ: The period is in (reciprocal) Hertz.
160 * - #PWM_PERIOD_COUNTS: The period is in timer counts.
162 * A PWM instance can be configured to interpret the duty as one of three
164 * - #PWM_DUTY_US: The duty is in microseconds.
165 * - #PWM_DUTY_FRACTION: The duty is in a fractional part of the period
166 * where 0 is 0% and #PWM_DUTY_FRACTION_MAX is 100%.
167 * - #PWM_DUTY_COUNTS: The period is in timer counts and must be less than
170 * The idle level parameter is used to set the output to high/low when the
171 * PWM is not running (stopped or not started). The idle level can be
176 * The default PWM configuration is to set a duty of 0% with a 1MHz frequency.
177 * The default period units are in PWM_PERIOD_HZ and the default duty units
178 * are in PWM_DUTY_FRACTION. Finally, the default output idle level is
179 * PWM_IDLE_LOW. It is the application's responsibility to set the duty for
180 * each PWM output used.
182 * ### Controlling the PWM Duty Cycle #
184 * Once the PWM instance has been opened and started, the primary API used
185 * by the application will be #PWM_setDuty() to control the duty cycle of a
189 * PWM_setDuty(pwm, PWM_DUTY_FRACTION_MAX / 2); // Set 50% duty cycle
194 * The PWM driver interface module is joined (at link time) to an
195 * array of PWM_Config data structures named *PWM_config*.
196 * PWM_config is implemented in the application with each entry being a
197 * PWM instance. Each entry in *PWM_config* contains a:
198 * - (PWM_FxnTable *) to a set of functions that implement a PWM peripheral
199 * - (void *) data object that is associated with the PWM_FxnTable
200 * - (void *) hardware attributes that are associated with the PWM_FxnTable
202 * The PWM APIs are redirected to the device specific implementations
203 * using the PWM_FxnTable pointer of the PWM_config entry.
204 * In order to use device specific functions of the PWM driver directly,
205 * link in the correct driver library for your device and include the
206 * device specific PWM driver header file (which in turn includes PWM.h).
207 * For example, for the MSP432 family of devices, you would include the
208 * following header file:
210 * #include <ti/drivers/pwm/PWMTimerMSP432.h>
213 * ============================================================================
216 #ifndef ti_drivers_PWM__include
217 #define ti_drivers_PWM__include
226 * @brief Maximum duty (100%) when configuring duty cycle as a fraction of
229 #define PWM_DUTY_FRACTION_MAX ((uint32_t) ~0)
232 * Common PWM_control command code reservation offset.
233 * PWM driver implementations should offset command codes with PWM_CMD_RESERVED
234 * growing positively.
236 * Example implementation specific command codes:
238 * #define PWMXYZ_COMMAND0 (PWM_CMD_RESERVED + 0)
239 * #define PWMXYZ_COMMAND1 (PWM_CMD_RESERVED + 1)
242 #define PWM_CMD_RESERVED (32)
245 * Common PWM_control status code reservation offset.
246 * PWM driver implementations should offset status codes with
247 * PWM_STATUS_RESERVED growing negatively.
249 * Example implementation specific status codes:
251 * #define PWMXYZ_STATUS_ERROR0 (PWM_STATUS_RESERVED - 0)
252 * #define PWMXYZ_STATUS_ERROR1 (PWM_STATUS_RESERVED - 1)
253 * #define PWMXYZ_STATUS_ERROR2 (PWM_STATUS_RESERVED - 2)
256 #define PWM_STATUS_RESERVED (-32)
259 * @brief Success status code returned by:
260 * PWM_control(), PWM_setDuty(), PWM_setPeriod().
262 * Functions return PWM_STATUS_SUCCESS if the call was executed
265 #define PWM_STATUS_SUCCESS (0)
268 * @brief Generic error status code returned by PWM_control().
270 * PWM_control() returns PWM_STATUS_ERROR if the control code was not executed
273 #define PWM_STATUS_ERROR (-1)
276 * @brief An error status code returned by PWM_control() for undefined
279 * PWM_control() returns PWM_STATUS_UNDEFINEDCMD if the control code is not
280 * recognized by the driver implementation.
282 #define PWM_STATUS_UNDEFINEDCMD (-2)
285 * @brief An error status code returned by PWM_setPeriod().
287 * PWM_setPeriod() returns PWM_STATUS_INVALID_PERIOD if the period argument is
288 * invalid for the current configuration.
290 #define PWM_STATUS_INVALID_PERIOD (-3)
293 * @brief An error status code returned by PWM_setDuty().
295 * PWM_setDuty() returns PWM_STATUS_INVALID_DUTY if the duty cycle argument is
296 * invalid for the current configuration.
298 #define PWM_STATUS_INVALID_DUTY (-4)
301 * @brief PWM period unit definitions. Refer to device specific
302 * implementation if using PWM_PERIOD_COUNTS (raw PWM/Timer counts).
304 typedef enum PWM_Period_Units_ {
305 PWM_PERIOD_US, /* Period in microseconds */
306 PWM_PERIOD_HZ, /* Period in (reciprocal) Hertz
307 (for example 2MHz = 0.5us period) */
308 PWM_PERIOD_COUNTS /* Period in timer counts */
312 * @brief PWM duty cycle unit definitions. Refer to device specific
313 * implementation if using PWM_DUTY_COUNTS (raw PWM/Timer counts).
315 typedef enum PWM_Duty_Units_ {
316 PWM_DUTY_US, /* Duty cycle in microseconds */
317 PWM_DUTY_FRACTION, /* Duty as a fractional part of PWM_DUTY_FRACTION_MAX */
318 PWM_DUTY_COUNTS /* Duty in timer counts */
322 * @brief Idle output level when PWM is not running (stopped / not started).
324 typedef enum PWM_IdleLevel_ {
330 * @brief PWM Parameters
332 * PWM Parameters are used to with the PWM_open() call. Default values for
333 * these parameters are set using PWM_Params_init().
335 * @sa PWM_Params_init()
337 typedef struct PWM_Params_ {
338 PWM_Period_Units periodUnits; /*!< Units in which the period is specified */
339 uint32_t periodValue; /*!< PWM initial period */
340 PWM_Duty_Units dutyUnits; /*!< Units in which the duty is specified */
341 uint32_t dutyValue; /*!< PWM initial duty */
342 PWM_IdleLevel idleLevel; /*!< Pin output when PWM is stopped. */
343 void *custom; /*!< Custom argument used by driver
348 * @brief A handle that is returned from a PWM_open() call.
350 typedef struct PWM_Config_ *PWM_Handle;
353 * @brief A function pointer to a driver specific implementation of
356 typedef void (*PWM_CloseFxn) (PWM_Handle handle);
359 * @brief A function pointer to a driver specific implementation of
362 typedef int_fast16_t (*PWM_ControlFxn) (PWM_Handle handle, uint_fast16_t cmd,
365 * @brief A function pointer to a driver specific implementation of
368 typedef void (*PWM_InitFxn) (PWM_Handle handle);
371 * @brief A function pointer to a driver specific implementation of
374 typedef PWM_Handle (*PWM_OpenFxn) (PWM_Handle handle, PWM_Params *params);
377 * @brief A function pointer to a driver specific implementation of
380 typedef int_fast16_t (*PWM_SetDutyFxn) (PWM_Handle handle,
384 * @brief A function pointer to a driver specific implementation of
387 typedef int_fast16_t (*PWM_SetPeriodFxn) (PWM_Handle handle,
391 * @brief A function pointer to a driver specific implementation of
394 typedef void (*PWM_StartFxn) (PWM_Handle handle);
397 * @brief A function pointer to a driver specific implementation of
400 typedef void (*PWM_StopFxn) (PWM_Handle handle);
403 * @brief The definition of a PWM function table that contains the
404 * required set of functions to control a specific PWM driver
407 typedef struct PWM_FxnTable_ {
408 /*! Function to close the specified instance */
409 PWM_CloseFxn closeFxn;
410 /*! Function to driver implementation specific control function */
411 PWM_ControlFxn controlFxn;
412 /*! Function to initialize the given data object */
414 /*! Function to open the specified instance */
416 /*! Function to set the duty cycle for a specific instance */
417 PWM_SetDutyFxn setDutyFxn;
418 /*! Function to set the period for a specific instance */
419 PWM_SetPeriodFxn setPeriodFxn;
420 /*! Function to start the PWM output for a specific instance */
421 PWM_StartFxn startFxn;
422 /*! Function to stop the PWM output for a specific instance */
427 * @brief PWM Global configuration.
429 * The PWM_Config structure contains a set of pointers used to characterize
430 * the PWM driver implementation.
433 typedef struct PWM_Config_ {
434 /*! Pointer to a table of driver-specific implementations of PWM APIs */
435 PWM_FxnTable const *fxnTablePtr;
436 /*! Pointer to a driver specific data object */
438 /*! Pointer to a driver specific hardware attributes structure */
443 * @brief Function to close a PWM instance specified by the PWM handle.
445 * @pre PWM_open() must have been called first.
446 * @pre PWM_stop() must have been called first if PWM was started.
448 * @param handle A PWM handle returned from PWM_open().
454 extern void PWM_close(PWM_Handle handle);
457 * @brief Function performs implementation specific features on a given
460 * @pre PWM_open() must have been called first.
462 * @param handle A PWM handle returned from PWM_open().
464 * @param cmd A command value defined by the driver specific
467 * @param arg A pointer to an optional R/W (read/write) argument that
468 * is accompanied with cmd.
470 * @return A PWM_Status describing an error or success state. Negative values
471 * indicate an error occurred.
475 extern int_fast16_t PWM_control(PWM_Handle handle, uint_fast16_t cmd,
479 * @brief This function initializes the PWM module.
481 * @pre The PWM_config structure must exist and be persistent before this
482 * function can be called. This function must be called before any
483 * other PWM driver APIs. This function does not modify any peripheral
484 * registers & should only be called once.
486 extern void PWM_init(void);
489 * @brief This function opens a given PWM instance and sets the period,
490 * duty and idle level to those specified in the params argument.
492 * @param index Logical instance number for the PWM indexed into
493 * the PWM_config table.
495 * @param params Pointer to an parameter structure. If NULL default
498 * @return A PWM_Handle if successful or NULL on an error or if it has been
499 * opened already. If NULL is returned further PWM API calls will
500 * result in undefined behavior.
504 extern PWM_Handle PWM_open(uint_least8_t index, PWM_Params *params);
507 * @brief Function to initialize the PWM_Params structure to default values.
509 * @param params A pointer to PWM_Params structure for initialization.
511 * Defaults values are:
512 * Period units: PWM_PERIOD_HZ
514 * Duty cycle units: PWM_DUTY_FRACTION
516 * Idle level: PWM_IDLE_LOW
518 extern void PWM_Params_init(PWM_Params *params);
521 * @brief Function to set the duty cycle of the specified PWM handle. PWM
522 * instances run in active high output mode; 0% is always low output,
523 * 100% is always high output. This API can be called while the PWM
524 * is running & duty must always be lower than or equal to the period.
525 * If an error occurs while calling the function the PWM duty cycle
526 * will remain unchanged.
528 * @pre PWM_open() must have been called first.
530 * @param handle A PWM handle returned from PWM_open().
532 * @param duty Duty cycle in the units specified by the params used
535 * @return A PWM status describing an error or success. Negative values
540 extern int_fast16_t PWM_setDuty(PWM_Handle handle, uint32_t duty);
543 * @brief Function to set the period of the specified PWM handle. This API
544 * can be called while the PWM is running & the period must always be
545 * larger than the duty cycle.
546 * If an error occurs while calling the function the PWM period
547 * will remain unchanged.
549 * @pre PWM_open() must have been called first.
551 * @param handle A PWM handle returned from PWM_open().
553 * @param period Period in the units specified by the params used
556 * @return A PWM status describing an error or success state. Negative values
561 extern int_fast16_t PWM_setPeriod(PWM_Handle handle, uint32_t period);
564 * @brief Function to start the specified PWM handle with current settings.
566 * @pre PWM_open() has to have been called first.
568 * @param handle A PWM handle returned from PWM_open().
573 extern void PWM_start(PWM_Handle handle);
576 * @brief Function to stop the specified PWM handle. Output will set to the
577 * idle level specified by params in PWM_open().
579 * @pre PWM_open() has to have been called first.
581 * @param handle A PWM handle returned from PWM_open().
586 extern void PWM_stop(PWM_Handle handle);
591 #endif /* ti_drivers_PWM__include */