drivers: pwm: stm32: support capturing on four channels
Previously the pwm capture only support capturing on channel 1 and 2, because the slave mode controller was used, which uses the signal TIxFP which is not available for channel 3 and 4. This commit adds optional support for four channel capturing by changing the method of capturing PWM signals to not use the slave mode controller to reset the counter register. Instead the counter is reset in the ISR. This will result in a slight loss of accuracy but is still within an acceptable range. Co-authored-by: Jeroen van Dooren <jeroen.van.dooren@nobleo.nl> Signed-off-by: Hein Wessels <heinwessels93@gmail.com>
This commit is contained in:
parent
3ecb4916b5
commit
1732651062
2 changed files with 256 additions and 130 deletions
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Linaro Limited.
|
||||
* Copyright (c) 2020 Teslabs Engineering S.L.
|
||||
* Copyright (c) 2023 Nobleo Technology
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -33,6 +34,22 @@ LOG_MODULE_REGISTER(pwm_stm32, CONFIG_PWM_LOG_LEVEL);
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_PWM_CAPTURE
|
||||
|
||||
/**
|
||||
* @brief Capture state when in 4-channel support mode
|
||||
*/
|
||||
enum capture_state {
|
||||
CAPTURE_STATE_IDLE = 0,
|
||||
CAPTURE_STATE_WAIT_FOR_UPDATE_EVENT = 1,
|
||||
CAPTURE_STATE_WAIT_FOR_PULSE_START = 2,
|
||||
CAPTURE_STATE_WAIT_FOR_PERIOD_END = 3
|
||||
};
|
||||
|
||||
/** Return the complimentary channel number
|
||||
* that is used to capture the end of the pulse.
|
||||
*/
|
||||
static const uint32_t complimentary_channel[] = {0, 2, 1, 4, 3};
|
||||
|
||||
struct pwm_stm32_capture_data {
|
||||
pwm_capture_callback_handler_t callback;
|
||||
void *user_data;
|
||||
|
@ -43,9 +60,16 @@ struct pwm_stm32_capture_data {
|
|||
bool capture_period;
|
||||
bool capture_pulse;
|
||||
bool continuous;
|
||||
uint8_t channel;
|
||||
|
||||
/* only used when four_channel_capture_support */
|
||||
enum capture_state state;
|
||||
};
|
||||
|
||||
/* first capture is always nonsense, second is nonsense when polarity changed */
|
||||
/* When PWM capture is done by resetting the counter with UIF then the
|
||||
* first capture is always nonsense, second is nonsense when polarity changed
|
||||
* This is not the case when using four-channel-support.
|
||||
*/
|
||||
#define SKIPPED_PWM_CAPTURES 2u
|
||||
|
||||
#endif /*CONFIG_PWM_CAPTURE*/
|
||||
|
@ -70,6 +94,7 @@ struct pwm_stm32_config {
|
|||
const struct pinctrl_dev_config *pcfg;
|
||||
#ifdef CONFIG_PWM_CAPTURE
|
||||
void (*irq_config_func)(const struct device *dev);
|
||||
const bool four_channel_capture_support;
|
||||
#endif /* CONFIG_PWM_CAPTURE */
|
||||
};
|
||||
|
||||
|
@ -115,6 +140,51 @@ static void (*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *,
|
|||
#endif
|
||||
};
|
||||
|
||||
/** Channel to capture get function mapping. */
|
||||
#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \
|
||||
!defined(CONFIG_SOC_SERIES_STM32F4X) && \
|
||||
!defined(CONFIG_SOC_SERIES_STM32G4X) && \
|
||||
!defined(CONFIG_SOC_SERIES_STM32MP1X)
|
||||
static uint32_t __maybe_unused (*const get_channel_capture[])(const TIM_TypeDef *) = {
|
||||
#else
|
||||
static uint32_t __maybe_unused (*const get_channel_capture[])(TIM_TypeDef *) = {
|
||||
#endif
|
||||
LL_TIM_IC_GetCaptureCH1, LL_TIM_IC_GetCaptureCH2,
|
||||
LL_TIM_IC_GetCaptureCH3, LL_TIM_IC_GetCaptureCH4
|
||||
};
|
||||
|
||||
|
||||
/** Channel to enable capture interrupt mapping. */
|
||||
static void __maybe_unused (*const enable_capture_interrupt[])(TIM_TypeDef *) = {
|
||||
LL_TIM_EnableIT_CC1, LL_TIM_EnableIT_CC2,
|
||||
LL_TIM_EnableIT_CC3, LL_TIM_EnableIT_CC4
|
||||
};
|
||||
|
||||
/** Channel to disable capture interrupt mapping. */
|
||||
static void __maybe_unused (*const disable_capture_interrupt[])(TIM_TypeDef *) = {
|
||||
LL_TIM_DisableIT_CC1, LL_TIM_DisableIT_CC2,
|
||||
LL_TIM_DisableIT_CC3, LL_TIM_DisableIT_CC4
|
||||
};
|
||||
|
||||
/** Channel to is capture active flag mapping. */
|
||||
#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \
|
||||
!defined(CONFIG_SOC_SERIES_STM32F4X) && \
|
||||
!defined(CONFIG_SOC_SERIES_STM32G4X) && \
|
||||
!defined(CONFIG_SOC_SERIES_STM32MP1X)
|
||||
static uint32_t __maybe_unused (*const is_capture_active[])(const TIM_TypeDef *) = {
|
||||
#else
|
||||
static uint32_t __maybe_unused (*const is_capture_active[])(TIM_TypeDef *) = {
|
||||
#endif
|
||||
LL_TIM_IsActiveFlag_CC1, LL_TIM_IsActiveFlag_CC2,
|
||||
LL_TIM_IsActiveFlag_CC3, LL_TIM_IsActiveFlag_CC4
|
||||
};
|
||||
|
||||
/** Channel to clearing capture flag mapping. */
|
||||
static void __maybe_unused (*const clear_capture_interrupt[])(TIM_TypeDef *) = {
|
||||
LL_TIM_ClearFlag_CC1, LL_TIM_ClearFlag_CC2,
|
||||
LL_TIM_ClearFlag_CC3, LL_TIM_ClearFlag_CC4
|
||||
};
|
||||
|
||||
/**
|
||||
* Obtain LL polarity from PWM flags.
|
||||
*
|
||||
|
@ -270,12 +340,10 @@ static int pwm_stm32_set_cycles(const struct device *dev, uint32_t channel,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PWM_CAPTURE
|
||||
if ((channel == 1u) || (channel == 2u)) {
|
||||
if (LL_TIM_IsEnabledIT_CC1(cfg->timer) ||
|
||||
LL_TIM_IsEnabledIT_CC2(cfg->timer)) {
|
||||
LOG_ERR("Cannot set PWM output, capture in progress");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (LL_TIM_IsEnabledIT_CC1(cfg->timer) || LL_TIM_IsEnabledIT_CC2(cfg->timer) ||
|
||||
LL_TIM_IsEnabledIT_CC3(cfg->timer) || LL_TIM_IsEnabledIT_CC4(cfg->timer)) {
|
||||
LOG_ERR("Cannot set PWM output, capture in progress");
|
||||
return -EBUSY;
|
||||
}
|
||||
#endif /* CONFIG_PWM_CAPTURE */
|
||||
|
||||
|
@ -391,8 +459,8 @@ static int pwm_stm32_set_cycles(const struct device *dev, uint32_t channel,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PWM_CAPTURE
|
||||
static int init_capture_channel(const struct device *dev, uint32_t channel,
|
||||
pwm_flags_t flags, uint32_t ll_channel)
|
||||
static int init_capture_channels(const struct device *dev, uint32_t channel,
|
||||
pwm_flags_t flags)
|
||||
{
|
||||
const struct pwm_stm32_config *cfg = dev->config;
|
||||
bool is_inverted = (flags & PWM_POLARITY_MASK) == PWM_POLARITY_INVERTED;
|
||||
|
@ -402,30 +470,21 @@ static int init_capture_channel(const struct device *dev, uint32_t channel,
|
|||
ic.ICPrescaler = TIM_ICPSC_DIV1;
|
||||
ic.ICFilter = LL_TIM_IC_FILTER_FDIV1;
|
||||
|
||||
if (ll_channel == LL_TIM_CHANNEL_CH1) {
|
||||
if (channel == 1u) {
|
||||
ic.ICActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
|
||||
ic.ICPolarity = is_inverted ? LL_TIM_IC_POLARITY_FALLING
|
||||
: LL_TIM_IC_POLARITY_RISING;
|
||||
} else {
|
||||
ic.ICActiveInput = LL_TIM_ACTIVEINPUT_INDIRECTTI;
|
||||
ic.ICPolarity = is_inverted ? LL_TIM_IC_POLARITY_RISING
|
||||
: LL_TIM_IC_POLARITY_FALLING;
|
||||
}
|
||||
} else {
|
||||
if (channel == 1u) {
|
||||
ic.ICActiveInput = LL_TIM_ACTIVEINPUT_INDIRECTTI;
|
||||
ic.ICPolarity = is_inverted ? LL_TIM_IC_POLARITY_RISING
|
||||
: LL_TIM_IC_POLARITY_FALLING;
|
||||
} else {
|
||||
ic.ICActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
|
||||
ic.ICPolarity = is_inverted ? LL_TIM_IC_POLARITY_FALLING
|
||||
: LL_TIM_IC_POLARITY_RISING;
|
||||
}
|
||||
/* Setup main channel */
|
||||
ic.ICActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
|
||||
ic.ICPolarity = is_inverted ? LL_TIM_IC_POLARITY_FALLING : LL_TIM_IC_POLARITY_RISING;
|
||||
|
||||
if (LL_TIM_IC_Init(cfg->timer, ch2ll[channel - 1], &ic) != SUCCESS) {
|
||||
LOG_ERR("Could not initialize main channel for PWM capture");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (LL_TIM_IC_Init(cfg->timer, ll_channel, &ic) != SUCCESS) {
|
||||
LOG_ERR("Could not initialize channel for PWM capture");
|
||||
/* Setup complimentary channel */
|
||||
ic.ICActiveInput = LL_TIM_ACTIVEINPUT_INDIRECTTI;
|
||||
ic.ICPolarity = is_inverted ? LL_TIM_IC_POLARITY_RISING : LL_TIM_IC_POLARITY_FALLING;
|
||||
|
||||
if (LL_TIM_IC_Init(cfg->timer, ch2ll[complimentary_channel[channel] - 1], &ic) != SUCCESS) {
|
||||
LOG_ERR("Could not initialize complimentary channel for PWM capture");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -437,12 +496,17 @@ static int pwm_stm32_configure_capture(const struct device *dev,
|
|||
pwm_capture_callback_handler_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
|
||||
/*
|
||||
* Capture is implemented using the slave mode controller.
|
||||
* This allows for high accuracy, but only CH1 and CH2 are supported.
|
||||
* Alternatively all channels could be supported with ISR based resets.
|
||||
* This is currently not implemented!
|
||||
* Capture is implemented in two different ways, depending on the
|
||||
* four-channel-capture-support setting in the node.
|
||||
* - Two Channel Support:
|
||||
* Only two channels (1 and 2) are available for capture. It uses
|
||||
* the slave mode controller to reset the counter on each edge.
|
||||
* - Four Channel Support:
|
||||
* All four channels are available for capture. Instead of the
|
||||
* slave mode controller it uses the ISR to reset the counter.
|
||||
* This is slightly less accurate, but still within acceptable
|
||||
* bounds.
|
||||
*/
|
||||
|
||||
const struct pwm_stm32_config *cfg = dev->config;
|
||||
|
@ -450,14 +514,21 @@ static int pwm_stm32_configure_capture(const struct device *dev,
|
|||
struct pwm_stm32_capture_data *cpt = &data->capture;
|
||||
int ret;
|
||||
|
||||
if ((channel != 1u) && (channel != 2u)) {
|
||||
LOG_ERR("PWM capture only supported on first two channels");
|
||||
return -ENOTSUP;
|
||||
if (!cfg->four_channel_capture_support) {
|
||||
if ((channel != 1u) && (channel != 2u)) {
|
||||
LOG_ERR("PWM capture only supported on first two channels");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
} else {
|
||||
if ((channel < 1u) || (channel > 4u)) {
|
||||
LOG_ERR("PWM capture only exists on channels 1, 2, 3 and 4.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (LL_TIM_IsEnabledIT_CC1(cfg->timer)
|
||||
|| LL_TIM_IsEnabledIT_CC2(cfg->timer)) {
|
||||
LOG_ERR("PWM Capture already in progress");
|
||||
if (LL_TIM_IsEnabledIT_CC1(cfg->timer) || LL_TIM_IsEnabledIT_CC2(cfg->timer) ||
|
||||
LL_TIM_IsEnabledIT_CC3(cfg->timer) || LL_TIM_IsEnabledIT_CC4(cfg->timer)) {
|
||||
LOG_ERR("PWM capture already in progress");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -466,7 +537,8 @@ static int pwm_stm32_configure_capture(const struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!IS_TIM_SLAVE_INSTANCE(cfg->timer)) {
|
||||
if (!cfg->four_channel_capture_support && !IS_TIM_SLAVE_INSTANCE(cfg->timer)) {
|
||||
/* slave mode is only used when not in four channel mode */
|
||||
LOG_ERR("Timer does not support slave mode for PWM capture");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
@ -480,23 +552,20 @@ static int pwm_stm32_configure_capture(const struct device *dev,
|
|||
/* Prevents faulty behavior while making changes */
|
||||
LL_TIM_SetSlaveMode(cfg->timer, LL_TIM_SLAVEMODE_DISABLED);
|
||||
|
||||
ret = init_capture_channel(dev, channel, flags, LL_TIM_CHANNEL_CH1);
|
||||
ret = init_capture_channels(dev, channel, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = init_capture_channel(dev, channel, flags, LL_TIM_CHANNEL_CH2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (!cfg->four_channel_capture_support) {
|
||||
if (channel == 1u) {
|
||||
LL_TIM_SetTriggerInput(cfg->timer, LL_TIM_TS_TI1FP1);
|
||||
} else {
|
||||
LL_TIM_SetTriggerInput(cfg->timer, LL_TIM_TS_TI2FP2);
|
||||
}
|
||||
LL_TIM_SetSlaveMode(cfg->timer, LL_TIM_SLAVEMODE_RESET);
|
||||
}
|
||||
|
||||
if (channel == 1u) {
|
||||
LL_TIM_SetTriggerInput(cfg->timer, LL_TIM_TS_TI1FP1);
|
||||
} else {
|
||||
LL_TIM_SetTriggerInput(cfg->timer, LL_TIM_TS_TI2FP2);
|
||||
}
|
||||
LL_TIM_SetSlaveMode(cfg->timer, LL_TIM_SLAVEMODE_RESET);
|
||||
|
||||
LL_TIM_EnableARRPreload(cfg->timer);
|
||||
if (!IS_TIM_32B_COUNTER_INSTANCE(cfg->timer)) {
|
||||
LL_TIM_SetAutoReload(cfg->timer, 0xffffu);
|
||||
|
@ -512,14 +581,22 @@ static int pwm_stm32_enable_capture(const struct device *dev, uint32_t channel)
|
|||
{
|
||||
const struct pwm_stm32_config *cfg = dev->config;
|
||||
struct pwm_stm32_data *data = dev->data;
|
||||
struct pwm_stm32_capture_data *cpt = &data->capture;
|
||||
|
||||
if ((channel != 1u) && (channel != 2u)) {
|
||||
LOG_ERR("PWM capture only supported on first two channels");
|
||||
return -EINVAL;
|
||||
if (!cfg->four_channel_capture_support) {
|
||||
if ((channel != 1u) && (channel != 2u)) {
|
||||
LOG_ERR("PWM capture only supported on first two channels");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
} else {
|
||||
if ((channel < 1u) || (channel > 4u)) {
|
||||
LOG_ERR("PWM capture only exists on channels 1, 2, 3 and 4.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (LL_TIM_IsEnabledIT_CC1(cfg->timer)
|
||||
|| LL_TIM_IsEnabledIT_CC2(cfg->timer)) {
|
||||
if (LL_TIM_IsEnabledIT_CC1(cfg->timer) || LL_TIM_IsEnabledIT_CC2(cfg->timer) ||
|
||||
LL_TIM_IsEnabledIT_CC3(cfg->timer) || LL_TIM_IsEnabledIT_CC4(cfg->timer)) {
|
||||
LOG_ERR("PWM capture already active");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -529,21 +606,22 @@ static int pwm_stm32_enable_capture(const struct device *dev, uint32_t channel)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->capture.skip_irq = SKIPPED_PWM_CAPTURES;
|
||||
cpt->channel = channel;
|
||||
cpt->state = CAPTURE_STATE_WAIT_FOR_PULSE_START;
|
||||
data->capture.skip_irq = cfg->four_channel_capture_support ? 0 : SKIPPED_PWM_CAPTURES;
|
||||
data->capture.overflows = 0u;
|
||||
LL_TIM_ClearFlag_CC1(cfg->timer);
|
||||
LL_TIM_ClearFlag_CC2(cfg->timer);
|
||||
|
||||
clear_capture_interrupt[channel - 1](cfg->timer);
|
||||
LL_TIM_ClearFlag_UPDATE(cfg->timer);
|
||||
|
||||
LL_TIM_SetUpdateSource(cfg->timer, LL_TIM_UPDATESOURCE_COUNTER);
|
||||
if (channel == 1u) {
|
||||
LL_TIM_EnableIT_CC1(cfg->timer);
|
||||
} else {
|
||||
LL_TIM_EnableIT_CC2(cfg->timer);
|
||||
}
|
||||
|
||||
enable_capture_interrupt[channel - 1](cfg->timer);
|
||||
|
||||
LL_TIM_CC_EnableChannel(cfg->timer, ch2ll[channel - 1]);
|
||||
LL_TIM_CC_EnableChannel(cfg->timer, ch2ll[complimentary_channel[channel] - 1]);
|
||||
LL_TIM_EnableIT_UPDATE(cfg->timer);
|
||||
LL_TIM_CC_EnableChannel(cfg->timer, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_CC_EnableChannel(cfg->timer, LL_TIM_CHANNEL_CH2);
|
||||
LL_TIM_GenerateEvent_UPDATE(cfg->timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -552,91 +630,130 @@ static int pwm_stm32_disable_capture(const struct device *dev, uint32_t channel)
|
|||
{
|
||||
const struct pwm_stm32_config *cfg = dev->config;
|
||||
|
||||
if ((channel != 1u) && (channel != 2u)) {
|
||||
LOG_ERR("PWM capture only supported on first two channels");
|
||||
return -EINVAL;
|
||||
if (!cfg->four_channel_capture_support) {
|
||||
if ((channel != 1u) && (channel != 2u)) {
|
||||
LOG_ERR("PWM capture only supported on first two channels");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
} else {
|
||||
if ((channel < 1u) || (channel > 4u)) {
|
||||
LOG_ERR("PWM capture only exists on channels 1, 2, 3 and 4.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
LL_TIM_SetUpdateSource(cfg->timer, LL_TIM_UPDATESOURCE_REGULAR);
|
||||
if (channel == 1u) {
|
||||
LL_TIM_DisableIT_CC1(cfg->timer);
|
||||
} else {
|
||||
LL_TIM_DisableIT_CC2(cfg->timer);
|
||||
}
|
||||
|
||||
disable_capture_interrupt[channel - 1](cfg->timer);
|
||||
|
||||
LL_TIM_DisableIT_UPDATE(cfg->timer);
|
||||
LL_TIM_CC_DisableChannel(cfg->timer, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_CC_DisableChannel(cfg->timer, LL_TIM_CHANNEL_CH2);
|
||||
LL_TIM_CC_DisableChannel(cfg->timer, ch2ll[channel - 1]);
|
||||
LL_TIM_CC_DisableChannel(cfg->timer, ch2ll[complimentary_channel[channel] - 1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_pwm_capture(const struct device *dev, uint32_t channel)
|
||||
{
|
||||
const struct pwm_stm32_config *cfg = dev->config;
|
||||
struct pwm_stm32_data *data = dev->data;
|
||||
struct pwm_stm32_capture_data *cpt = &data->capture;
|
||||
|
||||
if (channel == 1u) {
|
||||
cpt->period = LL_TIM_IC_GetCaptureCH1(cfg->timer);
|
||||
cpt->pulse = LL_TIM_IC_GetCaptureCH2(cfg->timer);
|
||||
} else {
|
||||
cpt->period = LL_TIM_IC_GetCaptureCH2(cfg->timer);
|
||||
cpt->pulse = LL_TIM_IC_GetCaptureCH1(cfg->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void pwm_stm32_isr(const struct device *dev)
|
||||
{
|
||||
const struct pwm_stm32_config *cfg = dev->config;
|
||||
struct pwm_stm32_data *data = dev->data;
|
||||
struct pwm_stm32_capture_data *cpt = &data->capture;
|
||||
int status = 0;
|
||||
uint32_t in_ch = LL_TIM_IsEnabledIT_CC1(cfg->timer) ? 1u : 2u;
|
||||
|
||||
if (cpt->skip_irq == 0u) {
|
||||
if (LL_TIM_IsActiveFlag_UPDATE(cfg->timer)) {
|
||||
LL_TIM_ClearFlag_UPDATE(cfg->timer);
|
||||
cpt->overflows++;
|
||||
}
|
||||
|
||||
if (LL_TIM_IsActiveFlag_CC1(cfg->timer)
|
||||
|| LL_TIM_IsActiveFlag_CC2(cfg->timer)) {
|
||||
LL_TIM_ClearFlag_CC1(cfg->timer);
|
||||
LL_TIM_ClearFlag_CC2(cfg->timer);
|
||||
|
||||
get_pwm_capture(dev, in_ch);
|
||||
|
||||
if (cpt->overflows) {
|
||||
LOG_ERR("counter overflow during PWM capture");
|
||||
status = -ERANGE;
|
||||
}
|
||||
|
||||
if (!cpt->continuous) {
|
||||
pwm_stm32_disable_capture(dev, in_ch);
|
||||
} else {
|
||||
cpt->overflows = 0u;
|
||||
}
|
||||
|
||||
if (cpt->callback != NULL) {
|
||||
cpt->callback(dev, in_ch,
|
||||
cpt->capture_period ? cpt->period : 0u,
|
||||
cpt->capture_pulse ? cpt->pulse : 0u,
|
||||
status, cpt->user_data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cpt->skip_irq != 0u) {
|
||||
if (LL_TIM_IsActiveFlag_UPDATE(cfg->timer)) {
|
||||
LL_TIM_ClearFlag_UPDATE(cfg->timer);
|
||||
}
|
||||
|
||||
if (LL_TIM_IsActiveFlag_CC1(cfg->timer)
|
||||
|| LL_TIM_IsActiveFlag_CC2(cfg->timer)) {
|
||||
|| LL_TIM_IsActiveFlag_CC2(cfg->timer)
|
||||
|| LL_TIM_IsActiveFlag_CC3(cfg->timer)
|
||||
|| LL_TIM_IsActiveFlag_CC4(cfg->timer)) {
|
||||
LL_TIM_ClearFlag_CC1(cfg->timer);
|
||||
LL_TIM_ClearFlag_CC2(cfg->timer);
|
||||
LL_TIM_ClearFlag_CC3(cfg->timer);
|
||||
LL_TIM_ClearFlag_CC4(cfg->timer);
|
||||
cpt->skip_irq--;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (LL_TIM_IsActiveFlag_UPDATE(cfg->timer)) {
|
||||
LL_TIM_ClearFlag_UPDATE(cfg->timer);
|
||||
if (cfg->four_channel_capture_support &&
|
||||
cpt->state == CAPTURE_STATE_WAIT_FOR_UPDATE_EVENT) {
|
||||
/* Special handling of UPDATE event in case it's triggered */
|
||||
cpt->state = CAPTURE_STATE_WAIT_FOR_PERIOD_END;
|
||||
} else {
|
||||
cpt->overflows++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg->four_channel_capture_support) {
|
||||
if (is_capture_active[cpt->channel - 1](cfg->timer) ||
|
||||
is_capture_active[complimentary_channel[cpt->channel] - 1](cfg->timer)) {
|
||||
clear_capture_interrupt[cpt->channel - 1](cfg->timer);
|
||||
clear_capture_interrupt
|
||||
[complimentary_channel[cpt->channel] - 1](cfg->timer);
|
||||
|
||||
cpt->period = get_channel_capture[cpt->channel - 1](cfg->timer);
|
||||
cpt->pulse = get_channel_capture
|
||||
[complimentary_channel[cpt->channel] - 1](cfg->timer);
|
||||
}
|
||||
} else {
|
||||
if (cpt->state == CAPTURE_STATE_WAIT_FOR_PULSE_START &&
|
||||
is_capture_active[cpt->channel - 1](cfg->timer)) {
|
||||
/* Reset the counter manually instead of automatically by HW
|
||||
* This sets the pulse-start at 0 and makes the pulse-end
|
||||
* and period related to that number. Sure we loose some
|
||||
* accuracy but it's within acceptable range.
|
||||
*
|
||||
* This is done through an UPDATE event to also reset
|
||||
* the prescalar. This could look like an overflow event
|
||||
* and might therefore require special handling.
|
||||
*/
|
||||
cpt->state = CAPTURE_STATE_WAIT_FOR_UPDATE_EVENT;
|
||||
LL_TIM_GenerateEvent_UPDATE(cfg->timer);
|
||||
|
||||
} else if ((cpt->state == CAPTURE_STATE_WAIT_FOR_UPDATE_EVENT ||
|
||||
cpt->state == CAPTURE_STATE_WAIT_FOR_PERIOD_END) &&
|
||||
is_capture_active[cpt->channel - 1](cfg->timer)) {
|
||||
cpt->state = CAPTURE_STATE_IDLE;
|
||||
/* The end of the period. Both capture channels should now contain
|
||||
* the timer value when the pulse and period ended respectively.
|
||||
*/
|
||||
cpt->pulse = get_channel_capture[complimentary_channel[cpt->channel] - 1]
|
||||
(cfg->timer);
|
||||
cpt->period = get_channel_capture[cpt->channel - 1](cfg->timer);
|
||||
}
|
||||
|
||||
clear_capture_interrupt[cpt->channel - 1](cfg->timer);
|
||||
|
||||
if (cpt->state != CAPTURE_STATE_IDLE) {
|
||||
/* Still waiting for a complete capture */
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpt->overflows) {
|
||||
LOG_ERR("counter overflow during PWM capture");
|
||||
status = -ERANGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cpt->continuous) {
|
||||
pwm_stm32_disable_capture(dev, cpt->channel);
|
||||
} else {
|
||||
cpt->overflows = 0u;
|
||||
cpt->state = CAPTURE_STATE_WAIT_FOR_PULSE_START;
|
||||
}
|
||||
|
||||
if (cpt->callback != NULL) {
|
||||
cpt->callback(dev, cpt->channel, cpt->capture_period ? cpt->period : 0u,
|
||||
cpt->capture_pulse ? cpt->pulse : 0u, status, cpt->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PWM_CAPTURE */
|
||||
|
||||
static int pwm_stm32_get_cycles_per_sec(const struct device *dev,
|
||||
|
@ -755,8 +872,9 @@ static void pwm_stm32_irq_config_func_##index(const struct device *dev) \
|
|||
(IRQ_CONNECT_AND_ENABLE_DEFAULT(index)) \
|
||||
); \
|
||||
}
|
||||
#define CAPTURE_INIT(index) \
|
||||
.irq_config_func = pwm_stm32_irq_config_func_##index
|
||||
#define CAPTURE_INIT(index) \
|
||||
.irq_config_func = pwm_stm32_irq_config_func_##index, \
|
||||
.four_channel_capture_support = DT_INST_PROP(index, four_channel_capture_support)
|
||||
#else
|
||||
#define IRQ_CONFIG_FUNC(index)
|
||||
#define CAPTURE_INIT(index)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue