2014-02-03 19:35:37 +01:00
|
|
|
/*
|
2015-10-21 12:39:00 +02:00
|
|
|
* Copyright (C) 2014-2015 Freie Universität Berlin
|
2014-02-03 19:35:37 +01:00
|
|
|
*
|
2015-10-21 12:39:00 +02:00
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
2014-02-03 19:35:37 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2015-11-19 15:54:52 +01:00
|
|
|
* @defgroup drivers_periph_pwm PWM
|
|
|
|
* @ingroup drivers_periph
|
2014-02-04 18:52:53 +01:00
|
|
|
* @brief Low-level PWM peripheral driver
|
2014-02-03 19:35:37 +01:00
|
|
|
*
|
2017-02-07 15:05:43 +01:00
|
|
|
* This interface enables access to CPU peripherals generating PWM signals. On
|
|
|
|
* most platforms, this interface will be implemented based on hardware timers,
|
|
|
|
* though some CPUs provide dedicated PWM peripherals.
|
|
|
|
*
|
|
|
|
* The characteristics of a PWM signal can be defined by three basic parameters,
|
|
|
|
* namely the frequency, the duty cycle, and the operational mode. This
|
|
|
|
* interface supports basic PWM generation in left-aligned, right-aligned, and
|
2017-02-13 09:37:16 +01:00
|
|
|
* center mode. Additionally the interface supports the definition of the used
|
2017-02-07 15:05:43 +01:00
|
|
|
* resolution, defining the granularity with which one can specify the duty
|
|
|
|
* cycle. This brings more flexibility to the configuration of the frequency,
|
|
|
|
* especially on systems with low system clocks.
|
|
|
|
*
|
|
|
|
* Typically, a single PWM device (e.g. hardware timer) supports PWM signal
|
|
|
|
* generation on multiple pins in parallel. While the duty cycle is selectable
|
|
|
|
* for each channel individually, the frequency and resolution are shared for
|
|
|
|
* all channels.
|
|
|
|
*
|
2017-02-13 09:37:16 +01:00
|
|
|
* The mapping/configuration of PWM devices (timers) and the used pins has to be
|
2017-02-07 15:05:43 +01:00
|
|
|
* done in the board configuration (the board's `periph_conf.h).
|
|
|
|
*
|
2017-02-13 09:37:16 +01:00
|
|
|
* When using the PWM interface, first thing you have to do is initialize the
|
|
|
|
* PWM device with the targeted mode, frequency, and resolution settings. Once
|
|
|
|
* the device is initialized, it will start the generation of PWM signals on all
|
2017-02-07 15:05:43 +01:00
|
|
|
* configured pins immediately, with an initial duty cycle of `0`. Use the
|
2017-02-13 09:37:16 +01:00
|
|
|
* pwm_set() function to change the duty cycle for a given channel. If you
|
2017-02-07 15:05:43 +01:00
|
|
|
* want to disable the PWM generation again, simply call pwm_poweroff().
|
|
|
|
*
|
2017-06-06 16:07:51 +02:00
|
|
|
* ## (Low-)Power implications
|
2017-02-07 15:05:43 +01:00
|
|
|
*
|
|
|
|
* After initialization, the a PWM peripheral **should** be powered on and
|
|
|
|
* active. When manually stopped using the pwm_poweroff() function, the PWM
|
|
|
|
* generation **should** be stopped for all channels and the PWM peripheral
|
|
|
|
* **should** be fully power off (e.g. through peripheral clock gating). Once
|
|
|
|
* being re-enabled by calling the pwm_poweron() function, the PWM peripheral
|
|
|
|
* **should** transparently continue its previously configured operation,
|
|
|
|
* including the last active duty cycle values.
|
|
|
|
*
|
|
|
|
* While a PWM device is active, some implementations might need to block
|
|
|
|
* certain power modes.
|
|
|
|
*
|
2014-12-04 10:03:15 +01:00
|
|
|
* @{
|
2014-10-25 15:37:04 +02:00
|
|
|
* @file
|
2014-02-04 18:52:53 +01:00
|
|
|
* @brief Low-level PWM peripheral driver interface definitions
|
2014-02-03 19:35:37 +01:00
|
|
|
*
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
|
|
*/
|
|
|
|
|
2015-10-21 12:39:00 +02:00
|
|
|
#ifndef PERIPH_PWM_H
|
|
|
|
#define PERIPH_PWM_H
|
2014-02-03 19:35:37 +01:00
|
|
|
|
2015-10-21 12:39:00 +02:00
|
|
|
#include <stdint.h>
|
2016-04-01 10:54:55 +02:00
|
|
|
#include <limits.h>
|
2015-10-21 12:39:00 +02:00
|
|
|
|
|
|
|
#include "periph_cpu.h"
|
2014-02-03 19:35:37 +01:00
|
|
|
#include "periph_conf.h"
|
|
|
|
|
2014-10-13 15:49:17 +02:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2015-10-21 12:39:00 +02:00
|
|
|
/**
|
|
|
|
* @brief Default PWM access macro
|
|
|
|
*/
|
|
|
|
#ifndef PWM_DEV
|
|
|
|
#define PWM_DEV(x) (x)
|
2014-02-03 19:35:37 +01:00
|
|
|
#endif
|
2015-10-21 12:39:00 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Default PWM undefined value
|
|
|
|
*/
|
|
|
|
#ifndef PWM_UNDEF
|
2021-11-12 16:26:36 +01:00
|
|
|
#define PWM_UNDEF (UINT_FAST8_MAX)
|
2014-02-03 19:35:37 +01:00
|
|
|
#endif
|
2015-10-21 12:39:00 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Default PWM type definition
|
|
|
|
*/
|
|
|
|
#ifndef HAVE_PWM_T
|
2021-11-12 16:26:36 +01:00
|
|
|
typedef uint_fast8_t pwm_t;
|
2014-03-26 17:11:24 +01:00
|
|
|
#endif
|
2014-02-03 19:35:37 +01:00
|
|
|
|
|
|
|
/**
|
2015-10-21 12:39:00 +02:00
|
|
|
* @brief Default PWM mode definition
|
2014-02-03 19:35:37 +01:00
|
|
|
*/
|
2015-10-21 12:39:00 +02:00
|
|
|
#ifndef HAVE_PWM_MODE_T
|
2014-02-03 19:35:37 +01:00
|
|
|
typedef enum {
|
2014-03-26 17:11:24 +01:00
|
|
|
PWM_LEFT, /*< use left aligned PWM */
|
|
|
|
PWM_RIGHT, /*< use right aligned PWM */
|
|
|
|
PWM_CENTER /*< use center aligned PWM */
|
2014-02-03 19:35:37 +01:00
|
|
|
} pwm_mode_t;
|
2015-10-21 12:39:00 +02:00
|
|
|
#endif
|
2014-02-03 19:35:37 +01:00
|
|
|
|
2019-10-21 15:49:57 +02:00
|
|
|
#ifdef MODULE_ARDUINO
|
|
|
|
/**
|
2023-06-23 15:42:08 +02:00
|
|
|
* @brief Mapping of an Arduino digital pin to the corresponding PWM dev and
|
|
|
|
* channel pair
|
2019-10-21 15:49:57 +02:00
|
|
|
*/
|
|
|
|
typedef struct {
|
2023-06-23 15:42:08 +02:00
|
|
|
pwm_t dev; /**< PWM device connected to the pin */
|
|
|
|
uint8_t chan; /**< PWM channel index */
|
|
|
|
uint8_t pin; /**< Arduino pin number */
|
2019-10-21 15:49:57 +02:00
|
|
|
} arduino_pwm_t;
|
|
|
|
#endif
|
|
|
|
|
2014-02-03 19:35:37 +01:00
|
|
|
/**
|
2015-10-21 12:39:00 +02:00
|
|
|
* @brief Initialize a PWM device
|
2014-05-14 10:46:15 +02:00
|
|
|
*
|
2015-10-21 12:39:00 +02:00
|
|
|
* The PWM module is based on virtual PWM devices, which can have one or more
|
|
|
|
* channels. The PWM devices can be configured to run with a given frequency and
|
|
|
|
* resolution, which are always identical for the complete device, hence for
|
|
|
|
* every channel on a device.
|
2014-05-14 10:46:15 +02:00
|
|
|
*
|
2015-10-21 12:39:00 +02:00
|
|
|
* The desired frequency and resolution may not be possible on a given device
|
|
|
|
* when chosen too large. In this case the PWM driver will always keep the
|
|
|
|
* resolution and decrease the frequency if needed. To verify the correct
|
|
|
|
* settings compare the returned value which is the actually set frequency.
|
2014-05-14 10:46:15 +02:00
|
|
|
*
|
2015-10-21 12:39:00 +02:00
|
|
|
* @param[in] dev PWM device to initialize
|
2014-02-27 18:22:31 +01:00
|
|
|
* @param[in] mode PWM mode, left, right or center aligned
|
2015-10-21 12:39:00 +02:00
|
|
|
* @param[in] freq PWM frequency in Hz
|
|
|
|
* @param[in] res PWM resolution
|
2014-02-27 18:22:31 +01:00
|
|
|
*
|
2015-10-21 12:39:00 +02:00
|
|
|
* @return actual PWM frequency on success
|
|
|
|
* @return 0 on error
|
2014-02-03 19:35:37 +01:00
|
|
|
*/
|
2015-10-21 12:39:00 +02:00
|
|
|
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res);
|
2014-02-03 19:35:37 +01:00
|
|
|
|
|
|
|
/**
|
2015-10-21 12:39:00 +02:00
|
|
|
* @brief Get the number of available channels
|
2014-05-14 10:46:15 +02:00
|
|
|
*
|
2015-10-21 12:39:00 +02:00
|
|
|
* @param[in] dev PWM device
|
|
|
|
*
|
|
|
|
* @return Number of channels available for the given device
|
|
|
|
*/
|
|
|
|
uint8_t pwm_channels(pwm_t dev);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the duty-cycle for a given channel of the given PWM device
|
|
|
|
*
|
|
|
|
* The duty-cycle is set in relation to the chosen resolution of the given
|
|
|
|
* device. If value > resolution, value is set to resolution.
|
2014-05-14 10:46:15 +02:00
|
|
|
*
|
2014-02-27 18:22:31 +01:00
|
|
|
* @param[in] dev the PWM device to set
|
|
|
|
* @param[in] channel the channel of the given device to set
|
|
|
|
* @param[in] value the desired duty-cycle to set
|
2014-02-03 19:35:37 +01:00
|
|
|
*/
|
2015-10-21 12:39:00 +02:00
|
|
|
void pwm_set(pwm_t dev, uint8_t channel, uint16_t value);
|
2014-02-03 19:35:37 +01:00
|
|
|
|
|
|
|
/**
|
2017-02-07 15:05:43 +01:00
|
|
|
* @brief Resume PWM generation on the given device
|
2014-05-14 10:46:15 +02:00
|
|
|
*
|
2017-02-07 15:05:43 +01:00
|
|
|
* When this function is called, the given PWM device is powered on and
|
2017-02-13 09:37:16 +01:00
|
|
|
* continues its previously configured operation. The duty cycle of each channel
|
|
|
|
* will be the value that was last set.
|
2014-02-27 18:22:31 +01:00
|
|
|
*
|
2017-02-07 15:05:43 +01:00
|
|
|
* This function must not be called before the PWM device was initialized.
|
2014-07-16 22:57:38 +02:00
|
|
|
*
|
2017-02-07 15:05:43 +01:00
|
|
|
* @param[in] dev device to start
|
2014-02-03 19:35:37 +01:00
|
|
|
*/
|
2014-07-16 22:57:38 +02:00
|
|
|
void pwm_poweron(pwm_t dev);
|
|
|
|
|
|
|
|
/**
|
2017-02-07 15:05:43 +01:00
|
|
|
* @brief Stop PWM generation on the given device
|
2014-07-16 22:57:38 +02:00
|
|
|
*
|
2017-02-13 09:37:16 +01:00
|
|
|
* This function stops the PWM generation on all configured channels for the
|
|
|
|
* given device and powers down the given PWM peripheral.
|
2014-07-16 22:57:38 +02:00
|
|
|
*
|
2017-02-07 15:05:43 +01:00
|
|
|
* @param[in] dev device to stop
|
2014-07-16 22:57:38 +02:00
|
|
|
*/
|
|
|
|
void pwm_poweroff(pwm_t dev);
|
|
|
|
|
2014-10-13 15:49:17 +02:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-10-21 12:39:00 +02:00
|
|
|
#endif /* PERIPH_PWM_H */
|
2014-02-03 19:35:37 +01:00
|
|
|
/** @} */
|