1 /* 2 * Copyright (c) 2015-2019, Texas Instruments Incorporated 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 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. 15 * 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. 19 * 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. 31 */ 32 /*!**************************************************************************** 33 * @file PWM.h 34 * @brief Pulse Width Modulation (PWM) driver 35 * 36 * @anchor ti_drivers_PWM_Overview 37 * # Overview # 38 * The PWM driver in TI-RTOS facilitates the generation of Pulse Width 39 * Modulated signals via simple and portable APIs. 40 * 41 * When a PWM instance is opened, the period, duty cycle and idle level are 42 * configured and the PWM is stopped (waveforms not generated until PWM_start() 43 * is called). The maximum period and duty supported is device dependent; 44 * refer to the implementation specific documentation for values. 45 * 46 * PWM outputs are active-high, meaning the duty will control the duration of 47 * high output on the pin (at 0% duty, the output is always low, at 100% duty, 48 * the output is always high). 49 * 50 * <hr> 51 * @anchor ti_drivers_PWM_Usage 52 * # Usage 53 * 54 * This documentation provides a basic @ref ti_drivers_PWM_Synopsis 55 * "usage summary" and a set of @ref ti_drivers_PWM_Examples "examples" 56 * in the form of commented code fragments. Detailed descriptions of the 57 * APIs are provided in subsequent sections. 58 * 59 * @anchor ti_drivers_PWM_Synopsis 60 * ## Synopsis 61 * @anchor ti_drivers_PWM_Synopsis_Code 62 * @code 63 * // Import PWM Driver definitions 64 * #include <ti/drivers/PWM.h> 65 * 66 * PWM_Handle pwm; 67 * PWM_Params pwmParams; 68 * uint32_t dutyValue; 69 * 70 * // Initialize the PWM driver. 71 * PWM_init(); 72 * 73 * // Initialize the PWM parameters 74 * PWM_Params_init(&pwmParams); 75 * pwmParams.idleLevel = PWM_IDLE_LOW; // Output low when PWM is not running 76 * pwmParams.periodUnits = PWM_PERIOD_HZ; // Period is in Hz 77 * pwmParams.periodValue = 1e6; // 1MHz 78 * pwmParams.dutyUnits = PWM_DUTY_FRACTION; // Duty is in fractional percentage 79 * pwmParams.dutyValue = 0; // 0% initial duty cycle 80 * 81 * // Open the PWM instance 82 * pwm = PWM_open(CONFIG_PWM0, &pwmParams); 83 * 84 * if (pwm == NULL) { 85 * // PWM_open() failed 86 * while (1); 87 * } 88 * 89 * PWM_start(pwm); // start PWM with 0% duty cycle 90 * 91 * dutyValue = (uint32_t) (((uint64_t) PWM_DUTY_FRACTION_MAX * 37) / 100); 92 * PWM_setDuty(pwm, dutyValue); // set duty cycle to 37% 93 * @endcode 94 * 95 * <hr> 96 * @anchor ti_drivers_PWM_Examples 97 * # Examples 98 * 99 * @li @ref ti_drivers_PWM_Examples_open "Opening a PWM instance" 100 * @li @ref ti_drivers_PWM_Examples_duty "Setting PWM duty" 101 * @li @ref ti_drivers_PWM_Examples_dutyperiod "Setting PWM Duty and Period" 102 * 103 * @anchor ti_drivers_PWM_Examples_open 104 * # Opening a PWM instance 105 * 106 * @code 107 * 108 * PWM_Handle pwm; 109 * PWM_Params pwmParams; 110 * 111 * PWM_init(); 112 * 113 * PWM_Params_init(&pwmParams); 114 * pwmParams.idleLevel = PWM_IDLE_LOW; 115 * pwmParams.periodUnits = PWM_PERIOD_HZ; 116 * pwmParams.periodValue = 1e6; 117 * pwmParams.dutyUnits = PWM_DUTY_FRACTION; 118 * pwmParams.dutyValue = 0; 119 * 120 * pwm = PWM_open(CONFIG_PWM0, &pwmParams); 121 * 122 * if (pwm == NULL) { 123 * // PWM_open() failed 124 * while (1); 125 * } 126 * @endcode 127 * 128 * @anchor ti_drivers_PWM_Examples_duty 129 * # Setting PWM duty 130 * 131 * Once the PWM instance has been opened and started, the primary API used 132 * by the application will be #PWM_setDuty() to control the duty cycle of a 133 * PWM pin: 134 * 135 * Below demonstrates setting the duty cycle in units of #PWM_DUTY_FRACTION 136 * to 45%. 137 * 138 * @code 139 * uint32_t dutyCycle; 140 * 141 * dutyCycle = (uint32_t) (((uint64_t) PWM_DUTY_FRACTION_MAX * 45) / 100); 142 * PWM_setDuty(pwm, dutyCycle); 143 * @endcode 144 * 145 * @anchor ti_drivers_PWM_Examples_dutyperiod 146 * # Setting PWM Duty and Period 147 * 148 * If an application needs to modify the duty and period of a running timer, 149 * an API is available to set both with as little interim time as possible. 150 * This minimises the possibility that a timeout will occur between one set 151 * call and the other. For low periods or for instances close to timeout, this 152 * API will pause the instance output briefly and must only be called when the 153 * PWM is already running. 154 * 155 * Below demonstrates setting the duty cycle to 75% of the new period (100us). 156 * 157 * @code 158 * uint32_t dutyCycle; 159 * uint32_t periodUs = 100; 160 * 161 * dutyCycle = (uint32_t) (((uint64_t) PWM_DUTY_FRACTION_MAX * 75) / 100); 162 * PWM_setDutyAndPeriod(pwm, dutyCycle, periodUs); 163 * @endcode 164 * 165 * ### Modes of Operation # 166 * 167 * A PWM instance can be configured to interpret the period as one of three 168 * units: 169 * - #PWM_PERIOD_US: The period is in microseconds. 170 * - #PWM_PERIOD_HZ: The period is in (reciprocal) Hertz. 171 * - #PWM_PERIOD_COUNTS: The period is in timer counts. 172 * 173 * A PWM instance can be configured to interpret the duty as one of three 174 * units: 175 * - #PWM_DUTY_US: The duty is in microseconds. 176 * - #PWM_DUTY_FRACTION: The duty is in a fractional part of 177 * #PWM_DUTY_FRACTION_MAX where 0 is 0% and 178 * #PWM_DUTY_FRACTION_MAX is 100%. See 179 * @ref ti_drivers_PWM_Examples_duty "Setting PWM duty" 180 * above. 181 * - #PWM_DUTY_COUNTS: The period is in timer counts and must be less than 182 * the period. 183 * 184 * The idle level parameter is used to set the output to high/low when the 185 * PWM is not running (stopped or not started). The idle level can be 186 * set to: 187 * - #PWM_IDLE_LOW 188 * - #PWM_IDLE_HIGH 189 * 190 * The default PWM configuration is to set a duty of 0% with a 1MHz frequency. 191 * The default period units are in #PWM_PERIOD_HZ and the default duty units 192 * are in #PWM_DUTY_FRACTION. Finally, the default output idle level is 193 * #PWM_IDLE_LOW. It is the application's responsibility to set the duty for 194 * each PWM output used. 195 * 196 * <hr> 197 * @anchor ti_drivers_PWM_Configuration 198 * # Configuration 199 * 200 * Refer to the @ref driver_configuration "Driver's Configuration" section 201 * for driver configuration information. 202 * <hr> 203 ***************************************************************************** 204 */ 205 206 #ifndef ti_drivers_PWM__include 207 #define ti_drivers_PWM__include 208 209 #include <stdint.h> 210 211 #ifdef __cplusplus 212 extern "C" { 213 #endif 214 215 216 /*! 217 * @brief Maximum duty (100%) when configuring duty cycle as a fraction of 218 * period. 219 */ 220 #define PWM_DUTY_FRACTION_MAX ((uint32_t) ~0) 221 222 /*! 223 * Common PWM_control command code reservation offset. 224 * PWM driver implementations should offset command codes with #PWM_CMD_RESERVED 225 * growing positively. 226 * 227 * Example implementation specific command codes: 228 * @code 229 * #define PWMXYZ_COMMAND0 (PWM_CMD_RESERVED + 0) 230 * #define PWMXYZ_COMMAND1 (PWM_CMD_RESERVED + 1) 231 * @endcode 232 */ 233 #define PWM_CMD_RESERVED (32) 234 235 /*! 236 * Common PWM_control status code reservation offset. 237 * PWM driver implementations should offset status codes with 238 * #PWM_STATUS_RESERVED growing negatively. 239 * 240 * Example implementation specific status codes: 241 * @code 242 * #define PWMXYZ_STATUS_ERROR0 (PWM_STATUS_RESERVED - 0) 243 * #define PWMXYZ_STATUS_ERROR1 (PWM_STATUS_RESERVED - 1) 244 * #define PWMXYZ_STATUS_ERROR2 (PWM_STATUS_RESERVED - 2) 245 * @endcode 246 */ 247 #define PWM_STATUS_RESERVED (-32) 248 249 /*! 250 * @brief Success status code returned by: 251 * #PWM_control(), #PWM_setDuty(), #PWM_setPeriod(). 252 * 253 * Functions return #PWM_STATUS_SUCCESS if the call was executed 254 * successfully. 255 */ 256 #define PWM_STATUS_SUCCESS (0) 257 258 /*! 259 * @brief Generic error status code returned by #PWM_control(). 260 * 261 * #PWM_control() returns #PWM_STATUS_ERROR if the control code was not executed 262 * successfully. 263 */ 264 #define PWM_STATUS_ERROR (-1) 265 266 /*! 267 * @brief An error status code returned by #PWM_control() for undefined 268 * command codes. 269 * 270 * #PWM_control() returns #PWM_STATUS_UNDEFINEDCMD if the control code is not 271 * recognized by the driver implementation. 272 */ 273 #define PWM_STATUS_UNDEFINEDCMD (-2) 274 275 /*! 276 * @brief An error status code returned by #PWM_setPeriod(). 277 * 278 * #PWM_setPeriod() returns #PWM_STATUS_INVALID_PERIOD if the period argument is 279 * invalid for the current configuration. 280 */ 281 #define PWM_STATUS_INVALID_PERIOD (-3) 282 283 /*! 284 * @brief An error status code returned by #PWM_setDuty(). 285 * 286 * #PWM_setDuty() returns #PWM_STATUS_INVALID_DUTY if the duty cycle argument is 287 * invalid for the current configuration. 288 */ 289 #define PWM_STATUS_INVALID_DUTY (-4) 290 291 /*! 292 * @brief PWM period unit definitions. Refer to device specific 293 * implementation if using #PWM_PERIOD_COUNTS (raw PWM/Timer counts). 294 */ 295 typedef enum { 296 PWM_PERIOD_US, /*!< Period in microseconds */ 297 PWM_PERIOD_HZ, /*!< Period in (reciprocal) Hertz 298 (for example 2MHz = 0.5us period) */ 299 PWM_PERIOD_COUNTS /*!< Period in timer counts */ 300 } PWM_Period_Units; 301 302 /*! 303 * @brief PWM duty cycle unit definitions. Refer to device specific 304 * implementation if using PWM_DUTY_COUNTS (raw PWM/Timer counts). 305 */ 306 typedef enum { 307 PWM_DUTY_US, /*!< Duty cycle in microseconds */ 308 PWM_DUTY_FRACTION, /*!< Duty as a fractional part of #PWM_DUTY_FRACTION_MAX. 309 * A duty cycle value of 0 will yield a 0% duty cycle 310 * while a duty cycle value of #PWM_DUTY_FRACTION_MAX 311 * will yield a duty cycle value of 100%. See 312 * @ref ti_drivers_PWM_Examples_duty "Setting PWM duty" 313 * above. */ 314 PWM_DUTY_COUNTS /*!< Duty in timer counts */ 315 } PWM_Duty_Units; 316 317 /*! 318 * @brief Idle output level when PWM is not running (stopped / not started). 319 */ 320 typedef enum { 321 PWM_IDLE_LOW = 0, 322 PWM_IDLE_HIGH = 1, 323 } PWM_IdleLevel; 324 325 /*! 326 * @brief PWM Parameters 327 * 328 * PWM Parameters are used to with the PWM_open() call. Default values for 329 * these parameters are set using PWM_Params_init(). 330 * 331 * @sa PWM_Params_init() 332 */ 333 typedef struct { 334 PWM_Period_Units periodUnits; /*!< Units in which the period is specified */ 335 uint32_t periodValue; /*!< PWM initial period */ 336 PWM_Duty_Units dutyUnits; /*!< Units in which the duty is specified */ 337 uint32_t dutyValue; /*!< PWM initial duty */ 338 PWM_IdleLevel idleLevel; /*!< Pin output when PWM is stopped. */ 339 void *custom; /*!< Custom argument used by driver 340 implementation */ 341 } PWM_Params; 342 343 /*! 344 * @brief A handle that is returned from a PWM_open() call. 345 */ 346 typedef struct PWM_Config_ *PWM_Handle; 347 348 /*! 349 * @brief A function pointer to a driver specific implementation of 350 * PWM_close(). 351 */ 352 typedef void (*PWM_CloseFxn) (PWM_Handle handle); 353 354 /*! 355 * @brief A function pointer to a driver specific implementation of 356 * PWM_control(). 357 */ 358 typedef int_fast16_t (*PWM_ControlFxn) (PWM_Handle handle, uint_fast16_t cmd, 359 void *arg); 360 /*! 361 * @brief A function pointer to a driver specific implementation of 362 * PWM_init(). 363 */ 364 typedef void (*PWM_InitFxn) (PWM_Handle handle); 365 366 /*! 367 * @brief A function pointer to a driver specific implementation of 368 * PWM_open(). 369 */ 370 typedef PWM_Handle (*PWM_OpenFxn) (PWM_Handle handle, PWM_Params *params); 371 372 /*! 373 * @brief A function pointer to a driver specific implementation of 374 * PWM_setDuty(). 375 */ 376 typedef int_fast16_t (*PWM_SetDutyFxn) (PWM_Handle handle, 377 uint32_t duty); 378 379 /*! 380 * @brief A function pointer to a driver specific implementation of 381 * PWM_setPeriod(). 382 */ 383 typedef int_fast16_t (*PWM_SetPeriodFxn) (PWM_Handle handle, 384 uint32_t period); 385 386 /*! 387 * @brief A function pointer to a driver specific implementation of 388 * PWM_setDutyAndPeriod(). 389 */ 390 typedef int_fast16_t (*PWM_SetDutyAndPeriodFxn) (PWM_Handle handle, 391 uint32_t duty, uint32_t period); 392 393 /*! 394 * @brief A function pointer to a driver specific implementation of 395 * PWM_start(). 396 */ 397 typedef void (*PWM_StartFxn) (PWM_Handle handle); 398 399 /*! 400 * @brief A function pointer to a driver specific implementation of 401 * PWM_stop(). 402 */ 403 typedef void (*PWM_StopFxn) (PWM_Handle handle); 404 405 /*! 406 * @brief The definition of a PWM function table that contains the 407 * required set of functions to control a specific PWM driver 408 * implementation. 409 */ 410 typedef struct { 411 /*! Function to close the specified instance */ 412 PWM_CloseFxn closeFxn; 413 /*! Function to driver implementation specific control function */ 414 PWM_ControlFxn controlFxn; 415 /*! Function to initialize the given data object */ 416 PWM_InitFxn initFxn; 417 /*! Function to open the specified instance */ 418 PWM_OpenFxn openFxn; 419 /*! Function to set the duty cycle for a specific instance */ 420 PWM_SetDutyFxn setDutyFxn; 421 /*! Function to set the period for a specific instance */ 422 PWM_SetPeriodFxn setPeriodFxn; 423 /*! Function to set the duty and the period for a specific instance */ 424 PWM_SetDutyAndPeriodFxn setDutyAndPeriodFxn; 425 /*! Function to start the PWM output for a specific instance */ 426 PWM_StartFxn startFxn; 427 /*! Function to stop the PWM output for a specific instance */ 428 PWM_StopFxn stopFxn; 429 } PWM_FxnTable; 430 431 /*! 432 * @brief PWM Global configuration. 433 * 434 * The PWM_Config structure contains a set of pointers used to characterize 435 * the PWM driver implementation. 436 * 437 */ 438 typedef struct PWM_Config_ { 439 /*! Pointer to a table of driver-specific implementations of PWM APIs */ 440 PWM_FxnTable const *fxnTablePtr; 441 /*! Pointer to a driver specific data object */ 442 void *object; 443 /*! Pointer to a driver specific hardware attributes structure */ 444 void const *hwAttrs; 445 } PWM_Config; 446 447 /*! 448 * @brief Function to close a PWM instance specified by the PWM handle. 449 * 450 * @pre PWM_open() must have been called first. 451 * @pre PWM_stop() must have been called first if PWM was started. 452 * 453 * @param[in] handle A PWM handle returned from PWM_open(). 454 * 455 * @sa PWM_open() 456 * @sa PWM_start() 457 * @sa PWM_stop() 458 */ 459 extern void PWM_close(PWM_Handle handle); 460 461 /*! 462 * @brief Function performs implementation specific features on a given 463 * PWM_Handle. 464 * 465 * @pre PWM_open() must have been called first. 466 * 467 * @param[in] handle A PWM handle returned from PWM_open(). 468 * 469 * @param[in] cmd A command value defined by the driver specific 470 * implementation. 471 * 472 * @param[in] arg A pointer to an optional R/W (read/write) argument that 473 * is accompanied with cmd. 474 * 475 * @retval #PWM_STATUS_SUCCESS The control call was successful. 476 * @retval #PWM_STATUS_ERROR The control call failed. 477 * 478 * @sa PWM_open() 479 */ 480 extern int_fast16_t PWM_control(PWM_Handle handle, uint_fast16_t cmd, 481 void *arg); 482 483 /*! 484 * @brief This function initializes the PWM module. 485 * 486 * @pre The PWM_config structure must exist and be persistent before this 487 * function can be called. This function must be called before any 488 * other PWM driver APIs. This function does not modify any peripheral 489 * registers & should only be called once. 490 */ 491 extern void PWM_init(void); 492 493 /*! 494 * @brief This function opens a given PWM instance and sets the period, 495 * duty and idle level to those specified in the params argument. 496 * 497 * @param[in] index Logical instance number for the PWM indexed into 498 * the PWM_config table. 499 * 500 * @param[in] params Pointer to an parameter structure. If NULL default 501 * values are used. 502 * 503 * @return A #PWM_Handle if successful or NULL on an error or if it has been 504 * opened already. If NULL is returned further PWM API calls will 505 * result in undefined behavior. 506 * 507 * @sa PWM_close() 508 */ 509 extern PWM_Handle PWM_open(uint_least8_t index, PWM_Params *params); 510 511 /*! 512 * @brief Function to initialize the PWM_Params structure to default values. 513 * 514 * @param[in] params A pointer to PWM_Params structure for initialization. 515 * 516 * Defaults values are: 517 * Period units: PWM_PERIOD_HZ 518 * Period: 1e6 (1MHz) 519 * Duty cycle units: PWM_DUTY_FRACTION 520 * Duty cycle: 0% 521 * Idle level: PWM_IDLE_LOW 522 */ 523 extern void PWM_Params_init(PWM_Params *params); 524 525 /*! 526 * @brief Function to set the duty cycle of the specified PWM handle. PWM 527 * instances run in active high output mode; 0% is always low output, 528 * 100% is always high output. This API can be called while the PWM 529 * is running & duty must always be lower than or equal to the period. 530 * If an error occurs while calling the function the PWM duty cycle 531 * will remain unchanged. 532 * 533 * @pre PWM_open() must have been called first. 534 * 535 * @param[in] handle A PWM handle returned from PWM_open(). 536 * 537 * @param[in] duty Duty cycle in the units and format specified by the params 538 * used in PWM_open(). 539 * 540 * @retval #PWM_STATUS_SUCCESS The duty was set successfully. 541 * @retval #PWM_STATUS_ERROR The duty was not set and remains unchanged. 542 * 543 * @sa PWM_open() 544 */ 545 extern int_fast16_t PWM_setDuty(PWM_Handle handle, uint32_t duty); 546 547 /*! 548 * @brief Function to set the period of the specified PWM handle. This API 549 * can be called while the PWM is running & the period must always be 550 * larger than the duty cycle. 551 * If an error occurs while calling the function the PWM period 552 * will remain unchanged. 553 * 554 * @pre PWM_open() must have been called first. 555 * 556 * @param[in] handle A PWM handle returned from PWM_open(). 557 * 558 * @param[in] period Period in the units specified by the params used 559 * in PWM_open(). 560 * 561 * @retval #PWM_STATUS_SUCCESS The period was set successfully. 562 * @retval #PWM_STATUS_ERROR The period was not set and remains unchanged. 563 * 564 * @sa PWM_open() 565 */ 566 extern int_fast16_t PWM_setPeriod(PWM_Handle handle, uint32_t period); 567 568 /*! 569 * @brief Function to set both the period and the duty cycle of the specified PWM handle. 570 * This API must be called while the PWM is running & the period must always be 571 * larger than the duty cycle. 572 * If an error occurs while calling the function the period and duty 573 * will remain unchanged. 574 * 575 * @note This API should only be called while the PWM is running. 576 * 577 * @note If the period is lower than a certain platform-specific amount, the output of the 578 * PWM timer may be paused to set these values. Some implementations may also pause 579 * the PWM if the remaining time before the next timeout is less than this value. This 580 * is to guard against an edge case where a timeout happens in between setting period 581 * and duty. 582 * 583 * @pre PWM_open() must have been called first. 584 * 585 * @param[in] handle A PWM handle returned from PWM_open(). 586 * 587 * @param[in] duty Duty cycle in the units and format specified by the params used 588 * in PWM_open(). 589 * 590 * @param[in] period Period in the units specified by the params used 591 * in PWM_open(). 592 * 593 * @retval #PWM_STATUS_SUCCESS The duty and period was set successfully. 594 * @retval #PWM_STATUS_ERROR The duty and period was not set and 595 remains unchanged. 596 * 597 * @sa PWM_open() 598 */ 599 extern int_fast16_t PWM_setDutyAndPeriod(PWM_Handle handle, uint32_t duty, uint32_t period); 600 601 /*! 602 * @brief Function to start the specified PWM handle with current settings. 603 * 604 * @pre PWM_open() has to have been called first. 605 * 606 * @param[in] handle A PWM handle returned from PWM_open(). 607 * 608 * @sa PWM_open() 609 * @sa PWM_stop() 610 */ 611 extern void PWM_start(PWM_Handle handle); 612 613 /*! 614 * @brief Function to stop the specified PWM handle. Output will set to the 615 * idle level specified by params in PWM_open(). 616 * 617 * @pre PWM_open() has to have been called first. 618 * 619 * @param[in] handle A PWM handle returned from PWM_open(). 620 * 621 * @sa PWM_open() 622 * @sa PWM_start() 623 */ 624 extern void PWM_stop(PWM_Handle handle); 625 626 #ifdef __cplusplus 627 } 628 #endif 629 #endif /* ti_drivers_PWM__include */ 630