From 0c9931cc9926e4c9fb19da8db232e0d1de1fc281 Mon Sep 17 00:00:00 2001 From: Martin Vajnar Date: Fri, 6 Jun 2025 17:08:02 +0200 Subject: [PATCH] espressif[risc-v|xtensa]: Check events when reading PCNT counter value Previously, if an event was generated in hardware after taking spin lock it was not correctly accounted for in current reading cycle. Now, we check for events and compensate count accordingly. Signed-off-by: Martin Vajnar --- arch/risc-v/src/common/espressif/esp_pcnt.c | 33 ++++++++++++++++++--- arch/xtensa/src/common/espressif/esp_pcnt.c | 33 ++++++++++++++++++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/arch/risc-v/src/common/espressif/esp_pcnt.c b/arch/risc-v/src/common/espressif/esp_pcnt.c index 7b2c268c25..b974612e43 100644 --- a/arch/risc-v/src/common/espressif/esp_pcnt.c +++ b/arch/risc-v/src/common/espressif/esp_pcnt.c @@ -388,12 +388,12 @@ static int IRAM_ATTR esp_pcnt_isr_default(int irq, void *context, unit = &pcnt_units[unit_id]; pcnt_ll_clear_intr_status(ctx.dev, PCNT_LL_UNIT_WATCH_EVENT(unit_id)); event_status = pcnt_ll_get_event_status(ctx.dev, unit_id); + flags = spin_lock_irqsave(&unit->lock); while (event_status) { int event_id = __builtin_ffs(event_status) - 1; event_status &= (event_status - 1); - flags = spin_lock_irqsave(&unit->lock); if (unit->config.accum_count) { if (event_id == PCNT_LL_WATCH_EVENT_LOW_LIMIT) @@ -406,7 +406,6 @@ static int IRAM_ATTR esp_pcnt_isr_default(int irq, void *context, } } - spin_unlock_irqrestore(&unit->lock, flags); if (unit->cb) { data.unit_id = unit_id; @@ -417,6 +416,8 @@ static int IRAM_ATTR esp_pcnt_isr_default(int irq, void *context, unit->cb(irq, context, &data); } } + + spin_unlock_irqrestore(&unit->lock, flags); } return 0; @@ -634,6 +635,9 @@ static int esp_pcnt_unit_get_count(struct cap_lowerhalf_s *dev, int *ret) { struct esp_pcnt_priv_s *priv = (struct esp_pcnt_priv_s *)dev; irqstate_t flags; + int32_t tmp_count; + uint32_t event_status; + uint32_t intr_status; if (!priv->unit_used) { @@ -642,8 +646,29 @@ static int esp_pcnt_unit_get_count(struct cap_lowerhalf_s *dev, int *ret) } flags = spin_lock_irqsave(&priv->lock); - *ret = pcnt_ll_get_count(ctx.dev, priv->unit_id) + - priv->accum_value; + tmp_count = pcnt_ll_get_count(ctx.dev, priv->unit_id); + + if (priv->config.accum_count) + { + intr_status = pcnt_ll_get_intr_status(ctx.dev); + if (intr_status & PCNT_LL_UNIT_WATCH_EVENT(priv->unit_id)) + { + event_status = pcnt_ll_get_event_status(ctx.dev, priv->unit_id); + if ((event_status & (1 << PCNT_LL_WATCH_EVENT_LOW_LIMIT)) && \ + (tmp_count >= (priv->config.low_limit / 2))) + { + tmp_count += priv->config.low_limit; + } + else if ((event_status & \ + (1 << PCNT_LL_WATCH_EVENT_HIGH_LIMIT)) && \ + (tmp_count <= (priv->config.high_limit / 2))) + { + tmp_count += priv->config.high_limit; + } + } + } + + *ret = tmp_count + priv->accum_value; spin_unlock_irqrestore(&priv->lock, flags); return OK; diff --git a/arch/xtensa/src/common/espressif/esp_pcnt.c b/arch/xtensa/src/common/espressif/esp_pcnt.c index 62c3f320cd..60ae5c9757 100644 --- a/arch/xtensa/src/common/espressif/esp_pcnt.c +++ b/arch/xtensa/src/common/espressif/esp_pcnt.c @@ -416,12 +416,12 @@ static int IRAM_ATTR esp_pcnt_isr_default(int irq, void *context, unit = &pcnt_units[unit_id]; pcnt_ll_clear_intr_status(ctx.dev, PCNT_LL_UNIT_WATCH_EVENT(unit_id)); event_status = pcnt_ll_get_event_status(ctx.dev, unit_id); + flags = spin_lock_irqsave(&unit->lock); while (event_status) { int event_id = __builtin_ffs(event_status) - 1; event_status &= (event_status - 1); - flags = spin_lock_irqsave(&unit->lock); if (unit->config.accum_count) { if (event_id == PCNT_LL_WATCH_EVENT_LOW_LIMIT) @@ -434,7 +434,6 @@ static int IRAM_ATTR esp_pcnt_isr_default(int irq, void *context, } } - spin_unlock_irqrestore(&unit->lock, flags); if (unit->cb) { data.unit_id = unit_id; @@ -445,6 +444,8 @@ static int IRAM_ATTR esp_pcnt_isr_default(int irq, void *context, unit->cb(irq, context, &data); } } + + spin_unlock_irqrestore(&unit->lock, flags); } return 0; @@ -671,6 +672,9 @@ static int esp_pcnt_unit_get_count(struct cap_lowerhalf_s *dev, int *ret) { struct esp_pcnt_priv_s *priv = (struct esp_pcnt_priv_s *)dev; irqstate_t flags; + int32_t tmp_count; + uint32_t event_status; + uint32_t intr_status; if (!priv->unit_used) { @@ -679,8 +683,29 @@ static int esp_pcnt_unit_get_count(struct cap_lowerhalf_s *dev, int *ret) } flags = spin_lock_irqsave(&priv->lock); - *ret = pcnt_ll_get_count(ctx.dev, priv->unit_id) + - priv->accum_value; + tmp_count = pcnt_ll_get_count(ctx.dev, priv->unit_id); + + if (priv->config.accum_count) + { + intr_status = pcnt_ll_get_intr_status(ctx.dev); + if (intr_status & PCNT_LL_UNIT_WATCH_EVENT(priv->unit_id)) + { + event_status = pcnt_ll_get_event_status(ctx.dev, priv->unit_id); + if ((event_status & (1 << PCNT_LL_WATCH_EVENT_LOW_LIMIT)) && \ + (tmp_count >= (priv->config.low_limit / 2))) + { + tmp_count += priv->config.low_limit; + } + else if ((event_status & \ + (1 << PCNT_LL_WATCH_EVENT_HIGH_LIMIT)) && \ + (tmp_count <= (priv->config.high_limit / 2))) + { + tmp_count += priv->config.high_limit; + } + } + } + + *ret = tmp_count + priv->accum_value; spin_unlock_irqrestore(&priv->lock, flags); return OK;