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
611__syscall int pwm_set_cycles(const struct device *dev, uint32_t channel,
612 uint32_t period, uint32_t pulse,
614
615static inline int z_impl_pwm_set_cycles(const struct device *dev,
616 uint32_t channel, uint32_t period,
618{
619 if (pulse > period) {
620 return -EINVAL;
621 }
622
623 return DEVICE_API_GET(pwm, dev)->set_cycles(dev, channel, period, pulse, flags);
624}
625
637__syscall int pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel,
638 uint64_t *cycles);
639
640static inline int z_impl_pwm_get_cycles_per_sec(const struct device *dev,
641 uint32_t channel,
642 uint64_t *cycles)
643{
644 return DEVICE_API_GET(pwm, dev)->get_cycles_per_sec(dev, channel, cycles);
645}
646
663static inline int pwm_set(const struct device *dev, uint32_t channel,
664 uint32_t period, uint32_t pulse, pwm_flags_t flags)
665{
666 int err;
667 uint64_t pulse_cycles;
668 uint64_t period_cycles;
669 uint64_t cycles_per_sec;
670
671 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
672 if (err < 0) {
673 return err;
674 }
675
676 period_cycles = (period * cycles_per_sec) / NSEC_PER_SEC;
677 if (period_cycles > UINT32_MAX) {
678 return -ENOTSUP;
679 }
680
681 pulse_cycles = (pulse * cycles_per_sec) / NSEC_PER_SEC;
682 if (pulse_cycles > UINT32_MAX) {
683 return -ENOTSUP;
684 }
685
686 return pwm_set_cycles(dev, channel, (uint32_t)period_cycles,
687 (uint32_t)pulse_cycles, flags);
688}
689
709static inline int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period,
710 uint32_t pulse)
711{
712 return pwm_set(spec->dev, spec->channel, period, pulse, spec->flags);
713}
714
730static inline int pwm_set_pulse_dt(const struct pwm_dt_spec *spec,
731 uint32_t pulse)
732{
733 return pwm_set(spec->dev, spec->channel, spec->period, pulse,
734 spec->flags);
735}
736
749static inline int pwm_cycles_to_usec(const struct device *dev, uint32_t channel,
750 uint32_t cycles, uint64_t *usec)
751{
752 int err;
753 uint64_t temp;
754 uint64_t cycles_per_sec;
755
756 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
757 if (err < 0) {
758 return err;
759 }
760
761 if (u64_mul_overflow(cycles, (uint64_t)USEC_PER_SEC, &temp)) {
762 return -ERANGE;
763 }
764
765 *usec = temp / cycles_per_sec;
766
767 return 0;
768}
769
782static inline int pwm_cycles_to_nsec(const struct device *dev, uint32_t channel,
783 uint32_t cycles, uint64_t *nsec)
784{
785 int err;
786 uint64_t temp;
787 uint64_t cycles_per_sec;
788
789 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
790 if (err < 0) {
791 return err;
792 }
793
794 if (u64_mul_overflow(cycles, (uint64_t)NSEC_PER_SEC, &temp)) {
795 return -ERANGE;
796 }
797
798 *nsec = temp / cycles_per_sec;
799
800 return 0;
801}
802
803#if defined(CONFIG_PWM_CAPTURE) || defined(__DOXYGEN__)
831static inline int pwm_configure_capture(const struct device *dev,
832 uint32_t channel, pwm_flags_t flags,
834 void *user_data)
835{
836 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
837
838 if (api->configure_capture == NULL) {
839 return -ENOSYS;
840 }
841
842 return api->configure_capture(dev, channel, flags, cb,
843 user_data);
844}
845#endif /* CONFIG_PWM_CAPTURE */
846
865__syscall int pwm_enable_capture(const struct device *dev, uint32_t channel);
866
867#ifdef CONFIG_PWM_CAPTURE
868static inline int z_impl_pwm_enable_capture(const struct device *dev,
869 uint32_t channel)
870{
871 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
872
873 if (api->enable_capture == NULL) {
874 return -ENOSYS;
875 }
876
877 return api->enable_capture(dev, channel);
878}
879#endif /* CONFIG_PWM_CAPTURE */
880
894__syscall int pwm_disable_capture(const struct device *dev, uint32_t channel);
895
896#ifdef CONFIG_PWM_CAPTURE
897static inline int z_impl_pwm_disable_capture(const struct device *dev,
898 uint32_t channel)
899{
900 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
901
902 if (api->disable_capture == NULL) {
903 return -ENOSYS;
904 }
905
906 return api->disable_capture(dev, channel);
907}
908#endif /* CONFIG_PWM_CAPTURE */
909
936__syscall int pwm_capture_cycles(const struct device *dev, uint32_t channel,
937 pwm_flags_t flags, uint32_t *period,
938 uint32_t *pulse, k_timeout_t timeout);
939
967static inline int pwm_capture_usec(const struct device *dev, uint32_t channel,
968 pwm_flags_t flags, uint64_t *period,
969 uint64_t *pulse, k_timeout_t timeout)
970{
971 int err;
972 uint32_t pulse_cycles;
973 uint32_t period_cycles;
974
975 err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
976 &pulse_cycles, timeout);
977 if (err < 0) {
978 return err;
979 }
980
981 err = pwm_cycles_to_usec(dev, channel, period_cycles, period);
982 if (err < 0) {
983 return err;
984 }
985
986 err = pwm_cycles_to_usec(dev, channel, pulse_cycles, pulse);
987 if (err < 0) {
988 return err;
989 }
990
991 return 0;
992}
993
1021static inline int pwm_capture_nsec(const struct device *dev, uint32_t channel,
1022 pwm_flags_t flags, uint64_t *period,
1023 uint64_t *pulse, k_timeout_t timeout)
1024{
1025 int err;
1026 uint32_t pulse_cycles;
1027 uint32_t period_cycles;
1028
1029 err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
1030 &pulse_cycles, timeout);
1031 if (err < 0) {
1032 return err;
1033 }
1034
1035 err = pwm_cycles_to_nsec(dev, channel, period_cycles, period);
1036 if (err < 0) {
1037 return err;
1038 }
1039
1040 err = pwm_cycles_to_nsec(dev, channel, pulse_cycles, pulse);
1041 if (err < 0) {
1042 return err;
1043 }
1044
1045 return 0;
1046}
1047
1048#if defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__)
1059static inline void pwm_init_event_callback(struct pwm_event_callback *callback,
1060 pwm_event_callback_handler_t handler, uint32_t channel,
1061 pwm_events_t event_mask)
1062{
1063 __ASSERT_NO_MSG(callback != NULL);
1064 __ASSERT_NO_MSG(handler != NULL);
1065
1066 callback->handler = handler;
1067 callback->channel = channel;
1068 callback->event_mask = event_mask;
1069}
1070
1085static inline int pwm_add_event_callback(const struct device *dev,
1086 struct pwm_event_callback *callback)
1087{
1088 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
1089
1090 if (api->manage_event_callback == NULL) {
1091 return -ENOSYS;
1092 }
1093
1094 return api->manage_event_callback(dev, callback, true);
1095}
1096
1109static inline int pwm_remove_event_callback(const struct device *dev,
1110 struct pwm_event_callback *callback)
1111{
1112 const struct pwm_driver_api *api = DEVICE_API_GET(pwm, dev);
1113
1114 if (api->manage_event_callback == NULL) {
1115 return -ENOSYS;
1116 }
1117
1118 return api->manage_event_callback(dev, callback, false);
1119}
1120#endif /* defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__) */
1121
1130static inline bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
1131{
1132 return device_is_ready(spec->dev);
1133}
1134
1135#ifdef __cplusplus
1136}
1137#endif
1138
1142
1143#include <zephyr/syscalls/pwm.h>
1144
1145#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:1375
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:1085
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:709
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:967
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:1021
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:782
static bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
Validate that the PWM device is ready.
Definition pwm.h:1130
static int pwm_remove_event_callback(const struct device *dev, struct pwm_event_callback *callback)
Remove an application event callback.
Definition pwm.h:1109
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:730
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:831
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:663
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:749
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:1059
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:39
#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
#define NULL
Definition iar_missing_defs.h:20
flags
Definition parser.h:97
__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.