Zephyr Project API 3.7.0
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 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
13#ifndef ZEPHYR_INCLUDE_DRIVERS_PWM_H_
14#define ZEPHYR_INCLUDE_DRIVERS_PWM_H_
15
25#include <errno.h>
26#include <stdint.h>
27
28#include <zephyr/device.h>
29#include <zephyr/devicetree.h>
30#include <zephyr/sys_clock.h>
32#include <zephyr/toolchain.h>
33
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
47/* Bit 0 is used for PWM_POLARITY_NORMAL/PWM_POLARITY_INVERTED */
48#define PWM_CAPTURE_TYPE_SHIFT 1U
49#define PWM_CAPTURE_TYPE_MASK (3U << PWM_CAPTURE_TYPE_SHIFT)
50#define PWM_CAPTURE_MODE_SHIFT 3U
51#define PWM_CAPTURE_MODE_MASK (1U << PWM_CAPTURE_MODE_SHIFT)
55#define PWM_CAPTURE_TYPE_PERIOD (1U << PWM_CAPTURE_TYPE_SHIFT)
56
58#define PWM_CAPTURE_TYPE_PULSE (2U << PWM_CAPTURE_TYPE_SHIFT)
59
61#define PWM_CAPTURE_TYPE_BOTH (PWM_CAPTURE_TYPE_PERIOD | \
62 PWM_CAPTURE_TYPE_PULSE)
63
65#define PWM_CAPTURE_MODE_SINGLE (0U << PWM_CAPTURE_MODE_SHIFT)
66
68#define PWM_CAPTURE_MODE_CONTINUOUS (1U << PWM_CAPTURE_MODE_SHIFT)
69
82
108
153#define PWM_DT_SPEC_GET_BY_NAME(node_id, name) \
154 { \
155 .dev = DEVICE_DT_GET(DT_PWMS_CTLR_BY_NAME(node_id, name)), \
156 .channel = DT_PWMS_CHANNEL_BY_NAME(node_id, name), \
157 .period = DT_PWMS_PERIOD_BY_NAME(node_id, name), \
158 .flags = DT_PWMS_FLAGS_BY_NAME(node_id, name), \
159 }
160
173#define PWM_DT_SPEC_INST_GET_BY_NAME(inst, name) \
174 PWM_DT_SPEC_GET_BY_NAME(DT_DRV_INST(inst), name)
175
194#define PWM_DT_SPEC_GET_BY_NAME_OR(node_id, name, default_value) \
195 COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
196 (PWM_DT_SPEC_GET_BY_NAME(node_id, name)), \
197 (default_value))
198
213#define PWM_DT_SPEC_INST_GET_BY_NAME_OR(inst, name, default_value) \
214 PWM_DT_SPEC_GET_BY_NAME_OR(DT_DRV_INST(inst), name, default_value)
215
258#define PWM_DT_SPEC_GET_BY_IDX(node_id, idx) \
259 { \
260 .dev = DEVICE_DT_GET(DT_PWMS_CTLR_BY_IDX(node_id, idx)), \
261 .channel = DT_PWMS_CHANNEL_BY_IDX(node_id, idx), \
262 .period = DT_PWMS_PERIOD_BY_IDX(node_id, idx), \
263 .flags = DT_PWMS_FLAGS_BY_IDX(node_id, idx), \
264 }
265
277#define PWM_DT_SPEC_INST_GET_BY_IDX(inst, idx) \
278 PWM_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)
279
297#define PWM_DT_SPEC_GET_BY_IDX_OR(node_id, idx, default_value) \
298 COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
299 (PWM_DT_SPEC_GET_BY_IDX(node_id, idx)), \
300 (default_value))
301
315#define PWM_DT_SPEC_INST_GET_BY_IDX_OR(inst, idx, default_value) \
316 PWM_DT_SPEC_GET_BY_IDX_OR(DT_DRV_INST(inst), idx, default_value)
317
328#define PWM_DT_SPEC_GET(node_id) PWM_DT_SPEC_GET_BY_IDX(node_id, 0)
329
340#define PWM_DT_SPEC_INST_GET(inst) PWM_DT_SPEC_GET(DT_DRV_INST(inst))
341
354#define PWM_DT_SPEC_GET_OR(node_id, default_value) \
355 PWM_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value)
356
369#define PWM_DT_SPEC_INST_GET_OR(inst, default_value) \
370 PWM_DT_SPEC_GET_OR(DT_DRV_INST(inst), default_value)
371
391typedef void (*pwm_capture_callback_handler_t)(const struct device *dev,
392 uint32_t channel,
393 uint32_t period_cycles,
394 uint32_t pulse_cycles,
395 int status, void *user_data);
396
402typedef int (*pwm_set_cycles_t)(const struct device *dev, uint32_t channel,
403 uint32_t period_cycles, uint32_t pulse_cycles,
405
410typedef int (*pwm_get_cycles_per_sec_t)(const struct device *dev,
411 uint32_t channel, uint64_t *cycles);
412
413#ifdef CONFIG_PWM_CAPTURE
418typedef int (*pwm_configure_capture_t)(const struct device *dev,
419 uint32_t channel, pwm_flags_t flags,
421 void *user_data);
422
427typedef int (*pwm_enable_capture_t)(const struct device *dev, uint32_t channel);
428
433typedef int (*pwm_disable_capture_t)(const struct device *dev,
434 uint32_t channel);
435#endif /* CONFIG_PWM_CAPTURE */
436
438__subsystem struct pwm_driver_api {
439 pwm_set_cycles_t set_cycles;
440 pwm_get_cycles_per_sec_t get_cycles_per_sec;
441#ifdef CONFIG_PWM_CAPTURE
442 pwm_configure_capture_t configure_capture;
443 pwm_enable_capture_t enable_capture;
444 pwm_disable_capture_t disable_capture;
445#endif /* CONFIG_PWM_CAPTURE */
446};
479__syscall int pwm_set_cycles(const struct device *dev, uint32_t channel,
480 uint32_t period, uint32_t pulse,
482
483static inline int z_impl_pwm_set_cycles(const struct device *dev,
484 uint32_t channel, uint32_t period,
486{
487 const struct pwm_driver_api *api =
488 (const struct pwm_driver_api *)dev->api;
489
490 if (pulse > period) {
491 return -EINVAL;
492 }
493
494 return api->set_cycles(dev, channel, period, pulse, flags);
495}
496
508__syscall int pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel,
509 uint64_t *cycles);
510
511static inline int z_impl_pwm_get_cycles_per_sec(const struct device *dev,
512 uint32_t channel,
513 uint64_t *cycles)
514{
515 const struct pwm_driver_api *api =
516 (const struct pwm_driver_api *)dev->api;
517
518 return api->get_cycles_per_sec(dev, channel, cycles);
519}
520
537static inline int pwm_set(const struct device *dev, uint32_t channel,
538 uint32_t period, uint32_t pulse, pwm_flags_t flags)
539{
540 int err;
541 uint64_t pulse_cycles;
542 uint64_t period_cycles;
543 uint64_t cycles_per_sec;
544
545 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
546 if (err < 0) {
547 return err;
548 }
549
550 period_cycles = (period * cycles_per_sec) / NSEC_PER_SEC;
551 if (period_cycles > UINT32_MAX) {
552 return -ENOTSUP;
553 }
554
555 pulse_cycles = (pulse * cycles_per_sec) / NSEC_PER_SEC;
556 if (pulse_cycles > UINT32_MAX) {
557 return -ENOTSUP;
558 }
559
560 return pwm_set_cycles(dev, channel, (uint32_t)period_cycles,
561 (uint32_t)pulse_cycles, flags);
562}
563
583static inline int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period,
584 uint32_t pulse)
585{
586 return pwm_set(spec->dev, spec->channel, period, pulse, spec->flags);
587}
588
604static inline int pwm_set_pulse_dt(const struct pwm_dt_spec *spec,
605 uint32_t pulse)
606{
607 return pwm_set(spec->dev, spec->channel, spec->period, pulse,
608 spec->flags);
609}
610
623static inline int pwm_cycles_to_usec(const struct device *dev, uint32_t channel,
624 uint32_t cycles, uint64_t *usec)
625{
626 int err;
627 uint64_t temp;
628 uint64_t cycles_per_sec;
629
630 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
631 if (err < 0) {
632 return err;
633 }
634
635 if (u64_mul_overflow(cycles, (uint64_t)USEC_PER_SEC, &temp)) {
636 return -ERANGE;
637 }
638
639 *usec = temp / cycles_per_sec;
640
641 return 0;
642}
643
656static inline int pwm_cycles_to_nsec(const struct device *dev, uint32_t channel,
657 uint32_t cycles, uint64_t *nsec)
658{
659 int err;
660 uint64_t temp;
661 uint64_t cycles_per_sec;
662
663 err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
664 if (err < 0) {
665 return err;
666 }
667
668 if (u64_mul_overflow(cycles, (uint64_t)NSEC_PER_SEC, &temp)) {
669 return -ERANGE;
670 }
671
672 *nsec = temp / cycles_per_sec;
673
674 return 0;
675}
676
677#if defined(CONFIG_PWM_CAPTURE) || defined(__DOXYGEN__)
706static inline int pwm_configure_capture(const struct device *dev,
707 uint32_t channel, pwm_flags_t flags,
709 void *user_data)
710{
711 const struct pwm_driver_api *api =
712 (const struct pwm_driver_api *)dev->api;
713
714 if (api->configure_capture == NULL) {
715 return -ENOSYS;
716 }
717
718 return api->configure_capture(dev, channel, flags, cb,
719 user_data);
720}
721#endif /* CONFIG_PWM_CAPTURE */
722
741__syscall int pwm_enable_capture(const struct device *dev, uint32_t channel);
742
743#ifdef CONFIG_PWM_CAPTURE
744static inline int z_impl_pwm_enable_capture(const struct device *dev,
745 uint32_t channel)
746{
747 const struct pwm_driver_api *api =
748 (const struct pwm_driver_api *)dev->api;
749
750 if (api->enable_capture == NULL) {
751 return -ENOSYS;
752 }
753
754 return api->enable_capture(dev, channel);
755}
756#endif /* CONFIG_PWM_CAPTURE */
757
772__syscall int pwm_disable_capture(const struct device *dev, uint32_t channel);
773
774#ifdef CONFIG_PWM_CAPTURE
775static inline int z_impl_pwm_disable_capture(const struct device *dev,
776 uint32_t channel)
777{
778 const struct pwm_driver_api *api =
779 (const struct pwm_driver_api *)dev->api;
780
781 if (api->disable_capture == NULL) {
782 return -ENOSYS;
783 }
784
785 return api->disable_capture(dev, channel);
786}
787#endif /* CONFIG_PWM_CAPTURE */
788
816__syscall int pwm_capture_cycles(const struct device *dev, uint32_t channel,
817 pwm_flags_t flags, uint32_t *period,
819
848static inline int pwm_capture_usec(const struct device *dev, uint32_t channel,
849 pwm_flags_t flags, uint64_t *period,
851{
852 int err;
853 uint32_t pulse_cycles;
854 uint32_t period_cycles;
855
856 err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
857 &pulse_cycles, timeout);
858 if (err < 0) {
859 return err;
860 }
861
862 err = pwm_cycles_to_usec(dev, channel, period_cycles, period);
863 if (err < 0) {
864 return err;
865 }
866
867 err = pwm_cycles_to_usec(dev, channel, pulse_cycles, pulse);
868 if (err < 0) {
869 return err;
870 }
871
872 return 0;
873}
874
903static inline int pwm_capture_nsec(const struct device *dev, uint32_t channel,
904 pwm_flags_t flags, uint64_t *period,
906{
907 int err;
908 uint32_t pulse_cycles;
909 uint32_t period_cycles;
910
911 err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
912 &pulse_cycles, timeout);
913 if (err < 0) {
914 return err;
915 }
916
917 err = pwm_cycles_to_nsec(dev, channel, period_cycles, period);
918 if (err < 0) {
919 return err;
920 }
921
922 err = pwm_cycles_to_nsec(dev, channel, pulse_cycles, pulse);
923 if (err < 0) {
924 return err;
925 }
926
927 return 0;
928}
929
938static inline bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
939{
940 return device_is_ready(spec->dev);
941}
942
943#ifdef __cplusplus
944}
945#endif
946
951#include <zephyr/syscalls/pwm.h>
952
953#endif /* ZEPHYR_INCLUDE_DRIVERS_PWM_H_ */
ZTEST_BMEM int timeout
Definition main.c:31
Devicetree main header.
System error numbers.
#define NSEC_PER_SEC
number of nanoseconds per second
Definition sys_clock.h:107
#define USEC_PER_SEC
number of microseconds per second
Definition sys_clock.h:104
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_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.
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:583
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:391
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:848
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:903
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:656
static bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
Validate that the PWM device is ready.
Definition pwm.h:938
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:604
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:706
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:537
uint16_t pwm_flags_t
Provides a type to hold PWM configuration flags.
Definition pwm.h:81
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:623
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.
#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
flags
Definition parser.h:96
__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:403
const void * api
Address of the API structure exposed by the device instance.
Definition device.h:409
Kernel timeout type.
Definition sys_clock.h:65
Container for PWM information specified in devicetree.
Definition pwm.h:98
pwm_flags_t flags
Flags.
Definition pwm.h:106
uint32_t channel
Channel number.
Definition pwm.h:102
uint32_t period
Period in nanoseconds.
Definition pwm.h:104
const struct device * dev
PWM device instance.
Definition pwm.h:100
Variables needed for system clock.
static const intptr_t user_data[5]
Definition main.c:588
Macros to abstract toolchain specific capabilities.