Zephyr API Documentation 4.4.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
pwm.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 Intel Corporation.
3 * Copyright (c) 2020-2021 Vestas Wind Systems A/S
4 * Copyright (c) 2025 Basalte bv
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
14
15#ifndef ZEPHYR_INCLUDE_DRIVERS_PWM_H_
16#define ZEPHYR_INCLUDE_DRIVERS_PWM_H_
17
31
32#include <errno.h>
33#include <stdint.h>
34
35#include <zephyr/device.h>
36#include <zephyr/devicetree.h>
37#include <zephyr/sys_clock.h>
39#include <zephyr/sys/slist.h>
40#include <zephyr/toolchain.h>
41
43
44#ifdef __cplusplus
45extern "C" {
46#endif
47
53
55/* Bit 0 is used for PWM_POLARITY_NORMAL/PWM_POLARITY_INVERTED */
56#define PWM_CAPTURE_TYPE_SHIFT 1U
57#define PWM_CAPTURE_TYPE_MASK (3U << PWM_CAPTURE_TYPE_SHIFT)
58#define PWM_CAPTURE_MODE_SHIFT 3U
59#define PWM_CAPTURE_MODE_MASK (1U << PWM_CAPTURE_MODE_SHIFT)
61
63#define PWM_CAPTURE_TYPE_PERIOD (1U << PWM_CAPTURE_TYPE_SHIFT)
64
66#define PWM_CAPTURE_TYPE_PULSE (2U << PWM_CAPTURE_TYPE_SHIFT)
67
69#define PWM_CAPTURE_TYPE_BOTH (PWM_CAPTURE_TYPE_PERIOD | \
70 PWM_CAPTURE_TYPE_PULSE)
71
73#define PWM_CAPTURE_MODE_SINGLE (0U << PWM_CAPTURE_MODE_SHIFT)
74
76#define PWM_CAPTURE_MODE_CONTINUOUS (1U << PWM_CAPTURE_MODE_SHIFT)
77
79
85
86#define PWM_EVENT_TYPE_SHIFT 0U
87
89#define PWM_EVENT_TYPE_PERIOD (1U << PWM_EVENT_TYPE_SHIFT)
90
97#define PWM_EVENT_TYPE_FAULT (2U << PWM_EVENT_TYPE_SHIFT)
98
103#define PWM_EVENT_TYPE_COMPARE_CAPTURE (4U << PWM_EVENT_TYPE_SHIFT)
104
106
115
117
123
125
151
196#define PWM_DT_SPEC_GET_BY_NAME(node_id, name) \
197 { \
198 .dev = DEVICE_DT_GET(DT_PWMS_CTLR_BY_NAME(node_id, name)), \
199 .channel = DT_PWMS_CHANNEL_BY_NAME(node_id, name), \
200 .period = DT_PWMS_PERIOD_BY_NAME(node_id, name), \
201 .flags = DT_PWMS_FLAGS_BY_NAME(node_id, name), \
202 }
203
216#define PWM_DT_SPEC_INST_GET_BY_NAME(inst, name) \
217 PWM_DT_SPEC_GET_BY_NAME(DT_DRV_INST(inst), name)
218
237#define PWM_DT_SPEC_GET_BY_NAME_OR(node_id, name, default_value) \
238 COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
239 (PWM_DT_SPEC_GET_BY_NAME(node_id, name)), \
240 (default_value))
241
256#define PWM_DT_SPEC_INST_GET_BY_NAME_OR(inst, name, default_value) \
257 PWM_DT_SPEC_GET_BY_NAME_OR(DT_DRV_INST(inst), name, default_value)
258
301#define PWM_DT_SPEC_GET_BY_IDX(node_id, idx) \
302 { \
303 .dev = DEVICE_DT_GET(DT_PWMS_CTLR_BY_IDX(node_id, idx)), \
304 .channel = DT_PWMS_CHANNEL_BY_IDX(node_id, idx), \
305 .period = DT_PWMS_PERIOD_BY_IDX(node_id, idx), \
306 .flags = DT_PWMS_FLAGS_BY_IDX(node_id, idx), \
307 }
308
320#define PWM_DT_SPEC_INST_GET_BY_IDX(inst, idx) \
321 PWM_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)
322
340#define PWM_DT_SPEC_GET_BY_IDX_OR(node_id, idx, default_value) \
341 COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
342 (PWM_DT_SPEC_GET_BY_IDX(node_id, idx)), \
343 (default_value))
344
358#define PWM_DT_SPEC_INST_GET_BY_IDX_OR(inst, idx, default_value) \
359 PWM_DT_SPEC_GET_BY_IDX_OR(DT_DRV_INST(inst), idx, default_value)
360
371#define PWM_DT_SPEC_GET(node_id) PWM_DT_SPEC_GET_BY_IDX(node_id, 0)
372
383#define PWM_DT_SPEC_INST_GET(inst) PWM_DT_SPEC_GET(DT_DRV_INST(inst))
384
397#define PWM_DT_SPEC_GET_OR(node_id, default_value) \
398 PWM_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value)
399
412#define PWM_DT_SPEC_INST_GET_OR(inst, default_value) \
413 PWM_DT_SPEC_GET_OR(DT_DRV_INST(inst), default_value)
414
434typedef void (*pwm_capture_callback_handler_t)(const struct device *dev,
435 uint32_t channel,
436 uint32_t period_cycles,
437 uint32_t pulse_cycles,
438 int status, void *user_data);
439
440struct pwm_event_callback;
441
456typedef void (*pwm_event_callback_handler_t)(const struct device *dev,
457 struct pwm_event_callback *callback, uint32_t channel,
458 pwm_events_t events);
459
485
490
495typedef int (*pwm_set_cycles_t)(const struct device *dev, uint32_t channel,
496 uint32_t period_cycles, uint32_t pulse_cycles,
498
503typedef int (*pwm_get_cycles_per_sec_t)(const struct device *dev,
504 uint32_t channel, uint64_t *cycles);
505
506#if defined(CONFIG_PWM_CAPTURE) || defined(__DOXYGEN__)
511typedef int (*pwm_configure_capture_t)(const struct device *dev,
512 uint32_t channel, pwm_flags_t flags,
514 void *user_data);
515
520typedef int (*pwm_enable_capture_t)(const struct device *dev, uint32_t channel);
521
526typedef int (*pwm_disable_capture_t)(const struct device *dev,
527 uint32_t channel);
528#endif /* CONFIG_PWM_CAPTURE */
529
530#if defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__)
535typedef int (*pwm_manage_event_callback_t)(const struct device *dev,
536 struct pwm_event_callback *callback, bool set);
537#endif /* CONFIG_PWM_EVENT */
538
542__subsystem struct pwm_driver_api {
551#if defined(CONFIG_PWM_CAPTURE) || defined(__DOXYGEN__)
567#endif /* CONFIG_PWM_CAPTURE */
568#if defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__)
574#endif /* CONFIG_PWM_EVENT */
575};
576
580
610__syscall int pwm_set_cycles(const struct device *dev, uint32_t channel,
611 uint32_t period, uint32_t pulse,
613
614static inline int z_impl_pwm_set_cycles(const struct device *dev,
615 uint32_t channel, uint32_t period,
617{
618 if (pulse > period) {
619 return -EINVAL;
620 }
621
622 return DEVICE_API_GET(pwm, dev)->set_cycles(dev, channel, period, pulse, flags);
623}
624
635__syscall int pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel,
636 uint64_t *cycles);
637
638static inline int z_impl_pwm_get_cycles_per_sec(const struct device *dev,
639 uint32_t channel,
640 uint64_t *cycles)
641{
642 return DEVICE_API_GET(pwm, dev)->get_cycles_per_sec(dev, channel, cycles);
643}
644
660static inline int pwm_set(const struct device *dev, uint32_t channel,
661 uint32_t period, uint32_t pulse, pwm_flags_t flags)
662{
663 int err;
664 uint64_t pulse_cycles;
665 uint64_t period_cycles;
666 uint64_t cycles_per_sec;
667
668 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
669 if (err < 0) {
670 return err;
671 }
672
673 period_cycles = (period * cycles_per_sec) / NSEC_PER_SEC;
674 if (period_cycles > UINT32_MAX) {
675 return -ENOTSUP;
676 }
677
678 pulse_cycles = (pulse * cycles_per_sec) / NSEC_PER_SEC;
679 if (pulse_cycles > UINT32_MAX) {
680 return -ENOTSUP;
681 }
682
683 return pwm_set_cycles(dev, channel, (uint32_t)period_cycles,
684 (uint32_t)pulse_cycles, flags);
685}
686
706static inline int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period,
707 uint32_t pulse)
708{
709 return pwm_set(spec->dev, spec->channel, period, pulse, spec->flags);
710}
711
727static inline int pwm_set_pulse_dt(const struct pwm_dt_spec *spec,
728 uint32_t pulse)
729{
730 return pwm_set(spec->dev, spec->channel, spec->period, pulse,
731 spec->flags);
732}
733
745static inline int pwm_cycles_to_usec(const struct device *dev, uint32_t channel,
746 uint32_t cycles, uint64_t *usec)
747{
748 int err;
749 uint64_t temp;
750 uint64_t cycles_per_sec;
751
752 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
753 if (err < 0) {
754 return err;
755 }
756
757 if (u64_mul_overflow(cycles, (uint64_t)USEC_PER_SEC, &temp)) {
758 return -ERANGE;
759 }
760
761 *usec = temp / cycles_per_sec;
762
763 return 0;
764}
765
777static inline int pwm_cycles_to_nsec(const struct device *dev, uint32_t channel,
778 uint32_t cycles, uint64_t *nsec)
779{
780 int err;
781 uint64_t temp;
782 uint64_t cycles_per_sec;
783
784 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
785 if (err < 0) {
786 return err;
787 }
788
789 if (u64_mul_overflow(cycles, (uint64_t)NSEC_PER_SEC, &temp)) {
790 return -ERANGE;
791 }
792
793 *nsec = temp / cycles_per_sec;
794
795 return 0;
796}
797
798#if defined(CONFIG_PWM_CAPTURE) || defined(__DOXYGEN__)
827static inline int pwm_configure_capture(const struct device *dev,
828 uint32_t channel, pwm_flags_t flags,
830 void *user_data)
831{
832 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
833
834 if (api->configure_capture == NULL) {
835 return -ENOSYS;
836 }
837
838 return api->configure_capture(dev, channel, flags, cb,
839 user_data);
840}
841#endif /* CONFIG_PWM_CAPTURE */
842
861__syscall int pwm_enable_capture(const struct device *dev, uint32_t channel);
862
863#ifdef CONFIG_PWM_CAPTURE
864static inline int z_impl_pwm_enable_capture(const struct device *dev,
865 uint32_t channel)
866{
867 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
868
869 if (api->enable_capture == NULL) {
870 return -ENOSYS;
871 }
872
873 return api->enable_capture(dev, channel);
874}
875#endif /* CONFIG_PWM_CAPTURE */
876
890__syscall int pwm_disable_capture(const struct device *dev, uint32_t channel);
891
892#ifdef CONFIG_PWM_CAPTURE
893static inline int z_impl_pwm_disable_capture(const struct device *dev,
894 uint32_t channel)
895{
896 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
897
898 if (api->disable_capture == NULL) {
899 return -ENOSYS;
900 }
901
902 return api->disable_capture(dev, channel);
903}
904#endif /* CONFIG_PWM_CAPTURE */
905
932__syscall int pwm_capture_cycles(const struct device *dev, uint32_t channel,
933 pwm_flags_t flags, uint32_t *period,
934 uint32_t *pulse, k_timeout_t timeout);
935
962static inline int pwm_capture_usec(const struct device *dev, uint32_t channel,
963 pwm_flags_t flags, uint64_t *period,
964 uint64_t *pulse, k_timeout_t timeout)
965{
966 int err;
967 uint32_t pulse_cycles;
968 uint32_t period_cycles;
969
970 err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
971 &pulse_cycles, timeout);
972 if (err < 0) {
973 return err;
974 }
975
976 err = pwm_cycles_to_usec(dev, channel, period_cycles, period);
977 if (err < 0) {
978 return err;
979 }
980
981 err = pwm_cycles_to_usec(dev, channel, pulse_cycles, pulse);
982 if (err < 0) {
983 return err;
984 }
985
986 return 0;
987}
988
1015static inline int pwm_capture_nsec(const struct device *dev, uint32_t channel,
1016 pwm_flags_t flags, uint64_t *period,
1017 uint64_t *pulse, k_timeout_t timeout)
1018{
1019 int err;
1020 uint32_t pulse_cycles;
1021 uint32_t period_cycles;
1022
1023 err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
1024 &pulse_cycles, timeout);
1025 if (err < 0) {
1026 return err;
1027 }
1028
1029 err = pwm_cycles_to_nsec(dev, channel, period_cycles, period);
1030 if (err < 0) {
1031 return err;
1032 }
1033
1034 err = pwm_cycles_to_nsec(dev, channel, pulse_cycles, pulse);
1035 if (err < 0) {
1036 return err;
1037 }
1038
1039 return 0;
1040}
1041
1042#if defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__)
1053static inline void pwm_init_event_callback(struct pwm_event_callback *callback,
1054 pwm_event_callback_handler_t handler, uint32_t channel,
1055 pwm_events_t event_mask)
1056{
1057 __ASSERT_NO_MSG(callback != NULL);
1058 __ASSERT_NO_MSG(handler != NULL);
1059
1060 callback->handler = handler;
1061 callback->channel = channel;
1062 callback->event_mask = event_mask;
1063}
1064
1078static inline int pwm_add_event_callback(const struct device *dev,
1079 struct pwm_event_callback *callback)
1080{
1081 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
1082
1083 if (api->manage_event_callback == NULL) {
1084 return -ENOSYS;
1085 }
1086
1087 return api->manage_event_callback(dev, callback, true);
1088}
1089
1101static inline int pwm_remove_event_callback(const struct device *dev,
1102 struct pwm_event_callback *callback)
1103{
1104 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
1105
1106 if (api->manage_event_callback == NULL) {
1107 return -ENOSYS;
1108 }
1109
1110 return api->manage_event_callback(dev, callback, false);
1111}
1112#endif /* defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__) */
1113
1122static inline bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
1123{
1124 return device_is_ready(spec->dev);
1125}
1126
1127#ifdef __cplusplus
1128}
1129#endif
1130
1134
1135#include <zephyr/syscalls/pwm.h>
1136
1137#endif /* ZEPHYR_INCLUDE_DRIVERS_PWM_H_ */
#define DEVICE_API_GET(_class, _dev)
Expands to the pointer of a device's API for a given class.
Definition device.h:1425
Devicetree main header.
System error numbers.
#define NSEC_PER_SEC
number of nanoseconds per second
Definition clock.h:113
#define USEC_PER_SEC
number of microseconds per second
Definition clock.h:110
bool device_is_ready(const struct device *dev)
Verify that a device is ready for use.
static bool u64_mul_overflow(uint64_t a, uint64_t b, uint64_t *result)
Multiply two unsigned 64-bit integers.
int(* pwm_set_cycles_t)(const struct device *dev, uint32_t channel, uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags)
Callback API to configure PWM pin period and pulse width.
Definition pwm.h:495
int(* pwm_disable_capture_t)(const struct device *dev, uint32_t channel)
Callback API to disable PWM capture.
Definition pwm.h:526
int(* pwm_get_cycles_per_sec_t)(const struct device *dev, uint32_t channel, uint64_t *cycles)
Callback API to obtain PWM cycles per second (frequency).
Definition pwm.h:503
int(* pwm_manage_event_callback_t)(const struct device *dev, struct pwm_event_callback *callback, bool set)
Callback API to manage event callbacks.
Definition pwm.h:535
int(* pwm_configure_capture_t)(const struct device *dev, uint32_t channel, pwm_flags_t flags, pwm_capture_callback_handler_t cb, void *user_data)
Callback API to configure PWM capture.
Definition pwm.h:511
int(* pwm_enable_capture_t)(const struct device *dev, uint32_t channel)
Callback API to enable PWM capture.
Definition pwm.h:520
int pwm_capture_cycles(const struct device *dev, uint32_t channel, pwm_flags_t flags, uint32_t *period, uint32_t *pulse, k_timeout_t timeout)
Capture a single PWM period/pulse width in clock cycles for a single PWM input.
static int pwm_add_event_callback(const struct device *dev, struct pwm_event_callback *callback)
Add an application event callback.
Definition pwm.h:1078
int pwm_disable_capture(const struct device *dev, uint32_t channel)
Disable PWM period/pulse width capture for a single PWM input.
static int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period, uint32_t pulse)
Set the period and pulse width in nanoseconds from a struct pwm_dt_spec (with custom period).
Definition pwm.h:706
void(* pwm_capture_callback_handler_t)(const struct device *dev, uint32_t channel, uint32_t period_cycles, uint32_t pulse_cycles, int status, void *user_data)
PWM capture callback handler function signature.
Definition pwm.h:434
int pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles)
Get the clock rate (cycles per second) for a single PWM output.
static int pwm_capture_usec(const struct device *dev, uint32_t channel, pwm_flags_t flags, uint64_t *period, uint64_t *pulse, k_timeout_t timeout)
Capture a single PWM period/pulse width in microseconds for a single PWM input.
Definition pwm.h:962
uint16_t pwm_events_t
Provides a type to hold PWM events.
Definition pwm.h:124
static int pwm_capture_nsec(const struct device *dev, uint32_t channel, pwm_flags_t flags, uint64_t *period, uint64_t *pulse, k_timeout_t timeout)
Capture a single PWM period/pulse width in nanoseconds for a single PWM input.
Definition pwm.h:1015
static int pwm_cycles_to_nsec(const struct device *dev, uint32_t channel, uint32_t cycles, uint64_t *nsec)
Convert from PWM cycles to nanoseconds.
Definition pwm.h:777
static bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
Validate that the PWM device is ready.
Definition pwm.h:1122
static int pwm_remove_event_callback(const struct device *dev, struct pwm_event_callback *callback)
Remove an application event callback.
Definition pwm.h:1101
static int pwm_set_pulse_dt(const struct pwm_dt_spec *spec, uint32_t pulse)
Set the period and pulse width in nanoseconds from a struct pwm_dt_spec.
Definition pwm.h:727
static int pwm_configure_capture(const struct device *dev, uint32_t channel, pwm_flags_t flags, pwm_capture_callback_handler_t cb, void *user_data)
Configure PWM period/pulse width capture for a single PWM input.
Definition pwm.h:827
int pwm_enable_capture(const struct device *dev, uint32_t channel)
Enable PWM period/pulse width capture for a single PWM input.
static int pwm_set(const struct device *dev, uint32_t channel, uint32_t period, uint32_t pulse, pwm_flags_t flags)
Set the period and pulse width in nanoseconds for a single PWM output.
Definition pwm.h:660
uint16_t pwm_flags_t
Provides a type to hold PWM configuration flags.
Definition pwm.h:116
static int pwm_cycles_to_usec(const struct device *dev, uint32_t channel, uint32_t cycles, uint64_t *usec)
Convert from PWM cycles to microseconds.
Definition pwm.h:745
void(* pwm_event_callback_handler_t)(const struct device *dev, struct pwm_event_callback *callback, uint32_t channel, pwm_events_t events)
PWM event callback handler function signature.
Definition pwm.h:456
static void pwm_init_event_callback(struct pwm_event_callback *callback, pwm_event_callback_handler_t handler, uint32_t channel, pwm_events_t event_mask)
Helper to initialize a struct pwm_event_callback properly.
Definition pwm.h:1053
int pwm_set_cycles(const struct device *dev, uint32_t channel, uint32_t period, uint32_t pulse, pwm_flags_t flags)
Set the period and pulse width for a single PWM output.
struct _snode sys_snode_t
Single-linked list node structure.
Definition slist.h:42
#define EINVAL
Invalid argument.
Definition errno.h:60
#define ENOSYS
Function not implemented.
Definition errno.h:82
#define ENOTSUP
Unsupported value.
Definition errno.h:114
#define ERANGE
Result too large.
Definition errno.h:72
Extra arithmetic and bit-manipulation functions.
flags
Definition parser.h:97
Header file for the single-linked list API.
__UINT32_TYPE__ uint32_t
Definition stdint.h:90
__UINT64_TYPE__ uint64_t
Definition stdint.h:91
__UINT16_TYPE__ uint16_t
Definition stdint.h:89
#define UINT32_MAX
Definition stdint.h:29
Runtime device structure (in ROM) per driver instance.
Definition device.h:513
Kernel timeout type.
Definition clock.h:65
<span class="mlabel">Driver Operations</span> PWM driver operations
Definition pwm.h:542
pwm_get_cycles_per_sec_t get_cycles_per_sec
<span class="op-badge op-req" title="This operation MUST be implemented by the driver....
Definition pwm.h:550
pwm_configure_capture_t configure_capture
<span class="op-badge op-opt" title="This operation MAY optionally be implemented by the driver....
Definition pwm.h:556
pwm_set_cycles_t set_cycles
<span class="op-badge op-req" title="This operation MUST be implemented by the driver....
Definition pwm.h:546
pwm_disable_capture_t disable_capture
<span class="op-badge op-opt" title="This operation MAY optionally be implemented by the driver....
Definition pwm.h:566
pwm_manage_event_callback_t manage_event_callback
<span class="op-badge op-opt" title="This operation MAY optionally be implemented by the driver....
Definition pwm.h:573
pwm_enable_capture_t enable_capture
<span class="op-badge op-opt" title="This operation MAY optionally be implemented by the driver....
Definition pwm.h:561
Container for PWM information specified in devicetree.
Definition pwm.h:141
pwm_flags_t flags
Flags.
Definition pwm.h:149
uint32_t channel
Channel number.
Definition pwm.h:145
uint32_t period
Period in nanoseconds.
Definition pwm.h:147
const struct device * dev
PWM device instance.
Definition pwm.h:143
PWM event callback structure.
Definition pwm.h:471
uint32_t channel
Channel the callback is interested in.
Definition pwm.h:480
pwm_events_t event_mask
A mask of events the callback is interested in.
Definition pwm.h:483
pwm_event_callback_handler_t handler
Actual callback function being called when relevant.
Definition pwm.h:477
Macros to abstract toolchain specific capabilities.