drivers: pwm: Add driver for xmc4xxx using ccu8 module
Adds driver for pwm on xmc4xxx using Capture Compare Unit 8 (CCU8) module. There are two CCU8 nodes with each one having four slices. Each slice has two output channels. Unlike CCU4, this module can generate complementary high-side/low-side signals for each output channel. A variable dead time can be added during the off to on transitions to make sure that the high-side/low-side signals are not on at the same time. Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
parent
23b6e4f507
commit
d8f955e375
@ -43,3 +43,15 @@
|
||||
drive-push-pull;
|
||||
hwctrl = "disabled";
|
||||
};
|
||||
|
||||
&pwm_out_p5_9_ccu80_ch4_high {
|
||||
drive-strength = "strong-medium-edge";
|
||||
drive-push-pull;
|
||||
hwctrl = "disabled";
|
||||
};
|
||||
|
||||
&pwm_out_p5_8_ccu80_ch0_low {
|
||||
drive-strength = "strong-medium-edge";
|
||||
drive-push-pull;
|
||||
hwctrl = "disabled";
|
||||
};
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
#include <infineon/xmc4700_F144x2048.dtsi>
|
||||
#include <infineon/xmc4700_F144x2048-intc.dtsi>
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include "xmc47_relax_kit-pinctrl.dtsi"
|
||||
#include "arduino_r3_connector.dtsi"
|
||||
|
||||
@ -19,6 +20,7 @@
|
||||
aliases {
|
||||
led0 = &led1;
|
||||
die-temp0 = &die_temp;
|
||||
pwm-led0 = &pwm_led1;
|
||||
};
|
||||
|
||||
leds {
|
||||
@ -32,6 +34,18 @@
|
||||
};
|
||||
};
|
||||
|
||||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
pwm_led1: pwm_led1 {
|
||||
pwms = <&pwm_ccu80 4 PWM_SEC(1) PWM_POLARITY_NORMAL>;
|
||||
label = "PWM LED1";
|
||||
};
|
||||
pwm_led2: pwm_led2 {
|
||||
pwms = <&pwm_ccu80 0 PWM_SEC(1) PWM_POLARITY_NORMAL>;
|
||||
label = "PWM LED2";
|
||||
};
|
||||
};
|
||||
|
||||
chosen {
|
||||
zephyr,sram = &psram1;
|
||||
zephyr,flash = &flash0;
|
||||
@ -135,3 +149,14 @@
|
||||
&gpio5 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* this example is not using the high-side/low-side signals of the same channel */
|
||||
/* the PWM signals are only used for the blink led example */
|
||||
&pwm_ccu80 {
|
||||
slice-prescaler = <15 15 15 15>;
|
||||
slice-deadtime-prescaler = <3 3 3 3>;
|
||||
channel-deadtime-high = <0 0 0 0 0 0 0 0>;
|
||||
channel-deadtime-low = <0 0 0 0 0 0 0 0>;
|
||||
pinctrl-0 = <&pwm_out_p5_9_ccu80_ch4_high &pwm_out_p5_8_ccu80_ch0_low>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
@ -35,6 +35,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_RPI_PICO pwm_rpi_pico.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_BBLED_XEC pwm_mchp_xec_bbled.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_INTEL_BLINKY pwm_intel_blinky.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU4 pwm_xmc4xxx_ccu4.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU8 pwm_xmc4xxx_ccu8.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c)
|
||||
|
||||
@ -91,4 +91,6 @@ source "drivers/pwm/Kconfig.intel_blinky"
|
||||
|
||||
source "drivers/pwm/Kconfig.xmc4xxx_ccu4"
|
||||
|
||||
source "drivers/pwm/Kconfig.xmc4xxx_ccu8"
|
||||
|
||||
endif # PWM
|
||||
|
||||
9
drivers/pwm/Kconfig.xmc4xxx_ccu8
Normal file
9
drivers/pwm/Kconfig.xmc4xxx_ccu8
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2023 SLB
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config PWM_XMC4XXX_CCU8
|
||||
bool "Infineon XMC4XXX CCU4 driver"
|
||||
default y
|
||||
depends on DT_HAS_INFINEON_XMC4XXX_CCU8_PWM_ENABLED
|
||||
help
|
||||
Enables Infineon XMC4XXX CCU8 PWM driver.
|
||||
171
drivers/pwm/pwm_xmc4xxx_ccu8.c
Normal file
171
drivers/pwm/pwm_xmc4xxx_ccu8.c
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2023 SLB
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT infineon_xmc4xxx_ccu8_pwm
|
||||
|
||||
#include <soc.h>
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include <zephyr/drivers/pwm.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
|
||||
#include <xmc_ccu8.h>
|
||||
#include <xmc_scu.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(pwm_xmc4xxx_ccu8, CONFIG_PWM_LOG_LEVEL);
|
||||
|
||||
#define NUM_SLICES 4
|
||||
#define NUM_CHANNELS (NUM_SLICES * 2)
|
||||
#define MAX_DEAD_TIME_VALUE 255
|
||||
#define MAX_SLICE_PRESCALER 15
|
||||
#define MAX_DEADTIME_PRESCALER 3
|
||||
#define SLICE_ADDR_FROM_MODULE(module_ptr, idx) ((uint32_t)(module_ptr) + ((idx) + 1) * 0x100)
|
||||
|
||||
struct pwm_xmc4xxx_ccu8_config {
|
||||
XMC_CCU8_MODULE_t *ccu8;
|
||||
const struct pinctrl_dev_config *pcfg;
|
||||
const uint8_t slice_prescaler[NUM_SLICES];
|
||||
const uint8_t slice_deadtime_prescaler[NUM_SLICES];
|
||||
const uint32_t deadtime_high_ns[NUM_CHANNELS];
|
||||
const uint32_t deadtime_low_ns[NUM_CHANNELS];
|
||||
};
|
||||
|
||||
static int pwm_xmc4xxx_ccu8_init(const struct device *dev)
|
||||
{
|
||||
const struct pwm_xmc4xxx_ccu8_config *config = dev->config;
|
||||
|
||||
/* enables the CCU8 clock and ungates clock to CCU8x */
|
||||
XMC_CCU8_EnableModule(config->ccu8);
|
||||
XMC_CCU8_StartPrescaler(config->ccu8);
|
||||
|
||||
for (int i = 0; i < NUM_SLICES; i++) {
|
||||
XMC_CCU8_SLICE_t *slice;
|
||||
XMC_CCU8_SLICE_DEAD_TIME_CONFIG_t deadtime_conf = {0};
|
||||
XMC_CCU8_SLICE_COMPARE_CONFIG_t slice_conf = {
|
||||
.prescaler_initval = config->slice_prescaler[i],
|
||||
.invert_out1 = 1,
|
||||
.invert_out3 = 1,
|
||||
};
|
||||
|
||||
if (config->slice_prescaler[i] > MAX_SLICE_PRESCALER) {
|
||||
LOG_ERR("Invalid slice_prescaler value %d. Range [0, 15]",
|
||||
config->slice_prescaler[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (config->slice_deadtime_prescaler[i] > MAX_DEADTIME_PRESCALER) {
|
||||
LOG_ERR("Invalid dead time prescaler value %d. Range [0, 3]",
|
||||
config->slice_deadtime_prescaler[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
slice = (XMC_CCU8_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu8, i);
|
||||
XMC_CCU8_SLICE_CompareInit(slice, &slice_conf);
|
||||
|
||||
deadtime_conf.div = config->slice_deadtime_prescaler[i];
|
||||
if (config->deadtime_high_ns[2*i] > 0 || config->deadtime_low_ns[2*i] > 0) {
|
||||
deadtime_conf.enable_dead_time_channel1 = 1;
|
||||
}
|
||||
deadtime_conf.channel1_st_path = config->deadtime_high_ns[2*i] > 0;
|
||||
deadtime_conf.channel1_inv_st_path = config->deadtime_low_ns[2*i] > 0;
|
||||
|
||||
if (config->deadtime_high_ns[2*i + 1] > 0 || config->deadtime_low_ns[2*i + 1] > 0) {
|
||||
deadtime_conf.enable_dead_time_channel2 = 1;
|
||||
}
|
||||
deadtime_conf.channel2_st_path = config->deadtime_high_ns[2*i + 1] > 0;
|
||||
deadtime_conf.channel2_inv_st_path = config->deadtime_low_ns[2*i + 1] > 0;
|
||||
|
||||
XMC_CCU8_SLICE_DeadTimeInit(slice, &deadtime_conf);
|
||||
}
|
||||
|
||||
return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
static int pwm_xmc4xxx_ccu8_set_cycles(const struct device *dev, uint32_t channel,
|
||||
uint32_t period_cycles, uint32_t pulse_cycles,
|
||||
pwm_flags_t flags)
|
||||
{
|
||||
const struct pwm_xmc4xxx_ccu8_config *config = dev->config;
|
||||
XMC_CCU8_SLICE_t *slice;
|
||||
uint32_t high_deadtime_value = 0, low_deadtime_value = 0;
|
||||
uint64_t cycles;
|
||||
int slice_idx = channel / 2;
|
||||
|
||||
if (channel >= NUM_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (period_cycles == 0 || period_cycles > UINT16_MAX + 1 || pulse_cycles > UINT16_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
slice = (XMC_CCU8_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu8, slice_idx);
|
||||
slice->PRS = period_cycles - 1;
|
||||
|
||||
if (channel & 0x1) {
|
||||
slice->CR2S = period_cycles - pulse_cycles;
|
||||
} else {
|
||||
slice->CR1S = period_cycles - pulse_cycles;
|
||||
}
|
||||
slice->PSL = flags & PWM_POLARITY_INVERTED;
|
||||
|
||||
/* set channel dead time */
|
||||
cycles = XMC_SCU_CLOCK_GetCcuClockFrequency() >> config->slice_prescaler[slice_idx];
|
||||
cycles >>= config->slice_deadtime_prescaler[slice_idx];
|
||||
high_deadtime_value = config->deadtime_high_ns[channel] * cycles / NSEC_PER_SEC;
|
||||
low_deadtime_value = config->deadtime_low_ns[channel] * cycles / NSEC_PER_SEC;
|
||||
|
||||
if (high_deadtime_value > MAX_DEAD_TIME_VALUE || low_deadtime_value > MAX_DEAD_TIME_VALUE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
XMC_CCU8_SLICE_SetDeadTimeValue(slice, channel & 0x1, high_deadtime_value,
|
||||
low_deadtime_value);
|
||||
|
||||
XMC_CCU8_EnableShadowTransfer(config->ccu8, BIT(slice_idx * 4));
|
||||
|
||||
/* start if not already running */
|
||||
XMC_CCU8_EnableClock(config->ccu8, slice_idx);
|
||||
XMC_CCU8_SLICE_StartTimer(slice);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_xmc4xxx_ccu8_get_cycles_per_sec(const struct device *dev, uint32_t channel,
|
||||
uint64_t *cycles)
|
||||
{
|
||||
const struct pwm_xmc4xxx_ccu8_config *config = dev->config;
|
||||
|
||||
if (channel >= NUM_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*cycles = XMC_SCU_CLOCK_GetCcuClockFrequency() >> config->slice_prescaler[channel / 2];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwm_driver_api pwm_xmc4xxx_ccu8_driver_api = {
|
||||
.set_cycles = pwm_xmc4xxx_ccu8_set_cycles,
|
||||
.get_cycles_per_sec = pwm_xmc4xxx_ccu8_get_cycles_per_sec,
|
||||
};
|
||||
|
||||
#define PWM_XMC4XXX_CCU8_INIT(n) \
|
||||
PINCTRL_DT_INST_DEFINE(n); \
|
||||
\
|
||||
static const struct pwm_xmc4xxx_ccu8_config config##n = { \
|
||||
.ccu8 = (CCU8_GLOBAL_TypeDef *)DT_INST_REG_ADDR(n), \
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||
.slice_prescaler = DT_INST_PROP(n, slice_prescaler), \
|
||||
.slice_deadtime_prescaler = DT_INST_PROP(n, slice_deadtime_prescaler), \
|
||||
.deadtime_high_ns = DT_INST_PROP(n, channel_deadtime_high), \
|
||||
.deadtime_low_ns = DT_INST_PROP(n, channel_deadtime_low), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, pwm_xmc4xxx_ccu8_init, NULL, NULL, &config##n, POST_KERNEL, \
|
||||
CONFIG_PWM_INIT_PRIORITY, &pwm_xmc4xxx_ccu8_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(PWM_XMC4XXX_CCU8_INIT)
|
||||
@ -242,4 +242,104 @@
|
||||
/omit-if-no-ref/ pwm_out_p3_6_ccu42_ch0: pwm_out_p3_6_ccu42_ch0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 6, 3)>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ pwm_out_p0_0_ccu80_ch2_low: pwm_out_p0_0_ccu80_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 0, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_1_ccu80_ch1_low: pwm_out_p0_1_ccu80_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 1, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_2_ccu80_ch0_low: pwm_out_p0_2_ccu80_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 2, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_3_ccu80_ch2_high: pwm_out_p0_3_ccu80_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 3, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_4_ccu80_ch1_high: pwm_out_p0_4_ccu80_ch1_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 4, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_5_ccu80_ch0_high: pwm_out_p0_5_ccu80_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 5, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_6_ccu80_ch3_high: pwm_out_p0_6_ccu80_ch3_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 6, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_9_ccu80_ch1_high: pwm_out_p0_9_ccu80_ch1_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 9, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_10_ccu80_ch0_high: pwm_out_p0_10_ccu80_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 10, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_11_ccu80_ch3_low: pwm_out_p0_11_ccu80_ch3_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 11, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_4_ccu80_ch3_low: pwm_out_p1_4_ccu80_ch3_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 4, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_4_ccu81_ch2_high: pwm_out_p1_4_ccu81_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 4, 4)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_5_ccu80_ch2_low: pwm_out_p1_5_ccu80_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_5_ccu81_ch1_high: pwm_out_p1_5_ccu81_ch1_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 4)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_10_ccu81_ch2_low: pwm_out_p1_10_ccu81_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 10, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_11_ccu81_ch1_low: pwm_out_p1_11_ccu81_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 11, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_12_ccu81_ch0_low: pwm_out_p1_12_ccu81_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 12, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_13_ccu81_ch2_high: pwm_out_p1_13_ccu81_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 13, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_14_ccu81_ch1_high: pwm_out_p1_14_ccu81_ch1_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 14, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_15_ccu81_ch0_high: pwm_out_p1_15_ccu81_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 15, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_0_ccu81_ch2_low: pwm_out_p2_0_ccu81_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 0, 2)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_1_ccu81_ch1_low: pwm_out_p2_1_ccu81_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 1, 2)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_2_ccu81_ch0_low: pwm_out_p2_2_ccu81_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 2, 2)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_6_ccu80_ch1_low: pwm_out_p2_6_ccu80_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 6, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_7_ccu80_ch0_low: pwm_out_p2_7_ccu80_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 7, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_8_ccu80_ch3_high: pwm_out_p2_8_ccu80_ch3_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 8, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_9_ccu80_ch2_high: pwm_out_p2_9_ccu80_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 9, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_14_ccu80_ch2_low: pwm_out_p2_14_ccu80_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 14, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_15_ccu80_ch1_low: pwm_out_p2_15_ccu80_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 15, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_0_ccu81_ch3_low: pwm_out_p5_0_ccu81_ch3_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_1_ccu81_ch3_high: pwm_out_p5_1_ccu81_ch3_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 1, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_2_ccu81_ch2_low: pwm_out_p5_2_ccu81_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 2, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_7_ccu81_ch0_high: pwm_out_p5_7_ccu81_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 7, 3)>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -811,4 +811,140 @@
|
||||
/omit-if-no-ref/ pwm_out_p6_5_ccu43_ch0: pwm_out_p6_5_ccu43_ch0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(6, 5, 3)>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ pwm_out_p0_0_ccu80_ch4_low: pwm_out_p0_0_ccu80_ch4_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 0, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_1_ccu80_ch2_low: pwm_out_p0_1_ccu80_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 1, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_2_ccu80_ch0_low: pwm_out_p0_2_ccu80_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 2, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_3_ccu80_ch4_high: pwm_out_p0_3_ccu80_ch4_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 3, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_4_ccu80_ch2_high: pwm_out_p0_4_ccu80_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 4, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_5_ccu80_ch0_high: pwm_out_p0_5_ccu80_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 5, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_6_ccu80_ch6_high: pwm_out_p0_6_ccu80_ch6_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 6, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_9_ccu80_ch3_high: pwm_out_p0_9_ccu80_ch3_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 9, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_10_ccu80_ch1_high: pwm_out_p0_10_ccu80_ch1_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 10, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p0_11_ccu80_ch6_low: pwm_out_p0_11_ccu80_ch6_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 11, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_4_ccu80_ch7_low: pwm_out_p1_4_ccu80_ch7_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 4, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_4_ccu81_ch4_high: pwm_out_p1_4_ccu81_ch4_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 4, 4)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_5_ccu80_ch5_low: pwm_out_p1_5_ccu80_ch5_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_5_ccu81_ch2_high: pwm_out_p1_5_ccu81_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 4)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_10_ccu81_ch4_low: pwm_out_p1_10_ccu81_ch4_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 10, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_11_ccu81_ch2_low: pwm_out_p1_11_ccu81_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 11, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_12_ccu81_ch0_low: pwm_out_p1_12_ccu81_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 12, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_13_ccu81_ch4_high: pwm_out_p1_13_ccu81_ch4_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 13, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_14_ccu81_ch2_high: pwm_out_p1_14_ccu81_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 14, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p1_15_ccu81_ch0_high: pwm_out_p1_15_ccu81_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 15, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_0_ccu81_ch4_low: pwm_out_p2_0_ccu81_ch4_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 0, 2)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_1_ccu81_ch2_low: pwm_out_p2_1_ccu81_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 1, 2)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_2_ccu81_ch0_low: pwm_out_p2_2_ccu81_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 2, 2)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_6_ccu80_ch3_low: pwm_out_p2_6_ccu80_ch3_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 6, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_7_ccu80_ch1_low: pwm_out_p2_7_ccu80_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 7, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_8_ccu80_ch7_high: pwm_out_p2_8_ccu80_ch7_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 8, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_9_ccu80_ch5_high: pwm_out_p2_9_ccu80_ch5_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 9, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_11_ccu80_ch5_high: pwm_out_p2_11_ccu80_ch5_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 11, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_12_ccu81_ch7_low: pwm_out_p2_12_ccu81_ch7_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 12, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_14_ccu80_ch4_low: pwm_out_p2_14_ccu80_ch4_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 14, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p2_15_ccu80_ch2_low: pwm_out_p2_15_ccu80_ch2_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 15, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_0_ccu81_ch7_low: pwm_out_p5_0_ccu81_ch7_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_1_ccu81_ch7_high: pwm_out_p5_1_ccu81_ch7_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 1, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_2_ccu81_ch5_low: pwm_out_p5_2_ccu81_ch5_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 2, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_3_ccu81_ch5_high: pwm_out_p5_3_ccu81_ch5_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 3, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_4_ccu81_ch3_low: pwm_out_p5_4_ccu81_ch3_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 4, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_5_ccu81_ch3_high: pwm_out_p5_5_ccu81_ch3_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 5, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_6_ccu81_ch1_low: pwm_out_p5_6_ccu81_ch1_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 6, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_7_ccu81_ch1_high: pwm_out_p5_7_ccu81_ch1_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 7, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_8_ccu80_ch0_low: pwm_out_p5_8_ccu80_ch0_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 8, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_9_ccu80_ch4_high: pwm_out_p5_9_ccu80_ch4_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 9, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_10_ccu80_ch2_high: pwm_out_p5_10_ccu80_ch2_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 10, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p5_11_ccu80_ch0_high: pwm_out_p5_11_ccu80_ch0_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 11, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p6_0_ccu81_ch6_low: pwm_out_p6_0_ccu81_ch6_low {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(6, 0, 3)>;
|
||||
};
|
||||
/omit-if-no-ref/ pwm_out_p6_1_ccu81_ch6_high: pwm_out_p6_1_ccu81_ch6_high {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(6, 1, 3)>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -215,6 +215,20 @@
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pwm_ccu80: ccu80@40020000 {
|
||||
compatible = "infineon,xmc4xxx-ccu8-pwm";
|
||||
reg = <0x40020000 0x4000>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pwm_ccu81: ccu81@40024000 {
|
||||
compatible = "infineon,xmc4xxx-ccu8-pwm";
|
||||
reg = <0x40024000 0x4000>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
126
dts/bindings/pwm/infineon,xmc4xxx-ccu8-pwm.yaml
Normal file
126
dts/bindings/pwm/infineon,xmc4xxx-ccu8-pwm.yaml
Normal file
@ -0,0 +1,126 @@
|
||||
# Copyright (c) 2023 SLB
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
Infineon XMC4XXX PWM Capture Compare Unit 8 (CCU8) module
|
||||
|
||||
The PWM CCU8 module can automatically generate a high-side
|
||||
and a low-side PWM signal, where the two signals are complementary
|
||||
to each other.
|
||||
|
||||
The module supports adding a dead time between the high-side and
|
||||
low-side PWM signals.
|
||||
|
||||
The dead time ensures that there is a delay before the PWM state
|
||||
transitions from 0 to 1, preventing the high-side and low-side
|
||||
switches from being on simultaneously.
|
||||
|
||||
There are two CCU8 modules with DTS node labels: pwm_ccu80 and
|
||||
pwm_ccu81. Each module has four slices, and each slice has
|
||||
two channels. A channel consists of a corresponding high-side
|
||||
and low-side PWM signal.
|
||||
|
||||
The CCU8 modules use the CCU clock source. Each slice applies
|
||||
a separate prescaler to divide the clock. The clock divider is
|
||||
defined by the 'slice-prescaler' property. Additionally, each
|
||||
slice has a dead time prescaler, which divides the slice clock
|
||||
for the dead time counter.
|
||||
|
||||
Device tree example:
|
||||
A node can define a 'pwm' field, usually referenced in a 'pwms'
|
||||
property, where the entries include the PWM module phandle,
|
||||
channel number, pulse period (in nanoseconds or set using
|
||||
PWM_XX() macros), and a channel
|
||||
flag (PWM_POLARITY_NORMAL/PWM_POLARITY_INVERTED).
|
||||
|
||||
The 'pwm_ccu8' node must define the following fields:
|
||||
&pwm_ccu80 {
|
||||
slice-prescaler = <15 15 15 15>;
|
||||
slice-deadtime-prescaler = <3 3 3 3>;
|
||||
channel-deadtime-high = <0 0 0 0 PWM_MSEC(100) 0 0 0>;
|
||||
channel-deadtime-low = <0 0 0 0 PWM_MSEC(100) 0 0 0>;
|
||||
pinctrl-0 = <&pwm_out_p5_9_ccu80_ch4_high &pwm_out_p0_0_ccu80_ch4_low>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
This will configure channel 4 with a 100msec deadtime on the high
|
||||
and low side PWM signals.
|
||||
|
||||
Another node can reference the PWM as follows:
|
||||
&test_node {
|
||||
...
|
||||
pwms = <&pwm_ccu80 0 PWM_SEC(1) PWM_POLARITY_NORMAL>;
|
||||
...
|
||||
};
|
||||
|
||||
The 'pwm_out_p{PORT}_{PIN}_ccu8{MODULE_IDX}_ch{CHANNEL_IDX}_{HIGH_LOW}'
|
||||
format is used for CCU8 pinctrl nodes. 'MODULE_IDX' and 'CHANNEL_IDX'
|
||||
refer to a specific 'pwm_ccu8x' module and channel, respectively.
|
||||
'PORT/PIN' defines the GPIO that the channel connects to.
|
||||
'HIGH_LOW' indicates whether the pin is for the high or low-side signal.
|
||||
|
||||
It's not necessary to specify both the high and low pinctrls. Only the low-side
|
||||
signal can, for example, be used as PWM, but note that the duty cycle of the
|
||||
low signal will be (1 - duty) as set via the API.
|
||||
|
||||
Note that a slice has two channels. Channels 0/1 are in slice 0,
|
||||
channels 2/3 are in slice 1, and so on. Each channel can have its own
|
||||
duty cycle and high/low dead times. But the pulse duration applies to
|
||||
both channels. Thus, when using the PWM control api to modify the pulse width
|
||||
on a channel 0, it will also be updated for channel 1 since they are
|
||||
in the same slice.
|
||||
|
||||
compatible: "infineon,xmc4xxx-ccu8-pwm"
|
||||
|
||||
include:
|
||||
- name: base.yaml
|
||||
- name: pwm-controller.yaml
|
||||
- name: pinctrl-device.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
pinctrl-0:
|
||||
required: true
|
||||
|
||||
pinctrl-names:
|
||||
required: true
|
||||
|
||||
slice-prescaler:
|
||||
type: array
|
||||
required: true
|
||||
description: |
|
||||
Defines the clock divider for each slice.
|
||||
The entry in the array will divide CCU clock by (2 << value).
|
||||
The range for the prescaler values is [0, 15].
|
||||
Reducing prescaler value will improve resolution but decrease the maximum period.
|
||||
|
||||
slice-deadtime-prescaler:
|
||||
type: array
|
||||
required: true
|
||||
description: |
|
||||
Defines the clock divider for dead time counter for each slice.
|
||||
The range for the values is [0, 3].
|
||||
Reducing prescaler value will improve dead time resolution but decrease the
|
||||
maximum dead time.
|
||||
|
||||
channel-deadtime-high:
|
||||
type: array
|
||||
required: true
|
||||
description: |
|
||||
Defines the dead time in nanoseconds for the high-side PWM signal for each channel.
|
||||
|
||||
channel-deadtime-low:
|
||||
type: array
|
||||
required: true
|
||||
description: |
|
||||
Defines the dead time in nanoseconds for the low-side PWM signal for each channel.
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
|
||||
pwm-cells:
|
||||
- channel
|
||||
- period
|
||||
- flags
|
||||
13
samples/basic/blinky_pwm/boards/xmc47_relax_kit.overlay
Normal file
13
samples/basic/blinky_pwm/boards/xmc47_relax_kit.overlay
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2023 SLB
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&pwm_led1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pwm_ccu80 {
|
||||
status = "okay";
|
||||
};
|
||||
@ -34,6 +34,9 @@ void z_arm_platform_init(void)
|
||||
XMC_SCU_CLOCK_SetSleepConfig(XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_SYSCLK_FPLL
|
||||
#ifdef CONFIG_PWM_XMC4XXX_CCU4
|
||||
| XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU
|
||||
#endif
|
||||
#ifdef CONFIG_PWM_XMC4XXX_CCU8
|
||||
| XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user