mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
Merge branch 'fix/mcpwm_cap_prescale_v5.5' into 'release/v5.5'
fix(mcpwm): correct the wrong capture prescale (v5.5) See merge request espressif/esp-idf!52506
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -140,7 +140,11 @@ typedef struct {
|
||||
int gpio_num; /*!< GPIO used capturing input signal */
|
||||
int intr_priority; /*!< MCPWM capture interrupt priority,
|
||||
if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
|
||||
uint32_t prescale; /*!< Prescale of input signal, effective frequency = cap_input_clk/prescale */
|
||||
uint32_t prescale; /*!< Input prescale ratio: same-edge capture spacing in input signal periods
|
||||
(e.g. rising-to-rising). Effective capture rate = input_rate / prescale.
|
||||
0 or 1: no prescaling (bypass); otherwise must be even.
|
||||
Prescaling is applied before edge selection; with prescale > 1,
|
||||
reported cap_edge may not match the physical GPIO edge. */
|
||||
|
||||
/// Extra configuration flags for capture channel
|
||||
struct extra_capture_channel_flags {
|
||||
|
||||
@@ -254,7 +254,10 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc
|
||||
esp_err_t ret = ESP_OK;
|
||||
mcpwm_cap_channel_t *cap_chan = NULL;
|
||||
ESP_GOTO_ON_FALSE(cap_timer && config && ret_cap_channel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE(config->prescale && config->prescale <= MCPWM_LL_MAX_CAPTURE_PRESCALE, ESP_ERR_INVALID_ARG, err, TAG, "invalid prescale");
|
||||
// prescale: same-edge ratio; 0/1 (bypass) or even.
|
||||
uint32_t prescale = config->prescale ? config->prescale : 1;
|
||||
ESP_GOTO_ON_FALSE((prescale == 1 || (prescale % 2) == 0) && (prescale / 2) < MCPWM_LL_MAX_CAPTURE_PRESCALE,
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid prescale");
|
||||
if (config->intr_priority) {
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
@@ -276,7 +279,7 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc
|
||||
mcpwm_ll_capture_enable_negedge(hal->dev, cap_chan_id, config->flags.neg_edge);
|
||||
mcpwm_ll_capture_enable_posedge(hal->dev, cap_chan_id, config->flags.pos_edge);
|
||||
mcpwm_ll_invert_input(hal->dev, cap_chan_id, config->flags.invert_cap_signal);
|
||||
mcpwm_ll_capture_set_prescale(hal->dev, cap_chan_id, config->prescale);
|
||||
mcpwm_ll_capture_set_prescale(hal->dev, cap_chan_id, prescale);
|
||||
|
||||
if (config->gpio_num >= 0) {
|
||||
// GPIO configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -7,10 +7,9 @@
|
||||
#include <inttypes.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "driver/mcpwm_cap.h"
|
||||
#include "driver/mcpwm_sync.h"
|
||||
#include "driver/gpio.h"
|
||||
@@ -262,3 +261,210 @@ TEST_CASE("mcpwm_capture_timer_sync_phase_lock", "[mcpwm]")
|
||||
TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(soft_sync));
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture input prescale: step GPIO high/low and see which edges fire a capture.
|
||||
* Frequency/pulse-width do not matter; only edge -> capture mapping does.
|
||||
*
|
||||
* For each cycle: drive rising edge, check; drive falling edge, check.
|
||||
* Do enough cycles to observe prescale phase + spacing (prescale * GROUPS).
|
||||
*/
|
||||
#define TEST_PRESCALE_GROUPS 8
|
||||
#define TEST_PRESCALE_SETTLE_US 50
|
||||
#define TEST_PRESCALE_MAX_CAPS 64
|
||||
|
||||
typedef struct {
|
||||
uint32_t count;
|
||||
mcpwm_capture_edge_t edges[TEST_PRESCALE_MAX_CAPS];
|
||||
uint32_t cycles[TEST_PRESCALE_MAX_CAPS];
|
||||
} test_prescale_ctx_t;
|
||||
|
||||
TEST_MCPWM_CALLBACK_ATTR
|
||||
static bool test_prescale_cap_cb(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *edata, void *user_data)
|
||||
{
|
||||
test_prescale_ctx_t *ctx = user_data;
|
||||
if (ctx->count < TEST_PRESCALE_MAX_CAPS) {
|
||||
ctx->edges[ctx->count++] = edata->cap_edge;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Drive one edge, wait for ISR, return true if a new capture arrived.
|
||||
static bool test_prescale_step(int gpio, int level, test_prescale_ctx_t *ctx,
|
||||
uint32_t cycle, mcpwm_capture_edge_t *out_edge)
|
||||
{
|
||||
uint32_t before = ctx->count;
|
||||
gpio_set_level(gpio, level);
|
||||
esp_rom_delay_us(TEST_PRESCALE_SETTLE_US);
|
||||
if (ctx->count == before) {
|
||||
return false;
|
||||
}
|
||||
ctx->cycles[before] = cycle;
|
||||
if (out_edge) {
|
||||
*out_edge = ctx->edges[before];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_prescale_check(int gpio, uint32_t prescale, bool pos_edge, bool neg_edge)
|
||||
{
|
||||
const bool both = pos_edge && neg_edge;
|
||||
// Enough full high/low cycles to get GROUPS captures per enabled edge type
|
||||
const uint32_t cycles = prescale * TEST_PRESCALE_GROUPS;
|
||||
const uint32_t expect = both ? (2 * TEST_PRESCALE_GROUPS) : TEST_PRESCALE_GROUPS;
|
||||
|
||||
// Recreate timer+channel every case so group register reset clears prior prescale phase.
|
||||
mcpwm_cap_timer_handle_t cap_timer = NULL;
|
||||
mcpwm_capture_timer_config_t cap_cfg = {
|
||||
.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_capture_timer(&cap_cfg, &cap_timer));
|
||||
TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
|
||||
TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
|
||||
|
||||
mcpwm_cap_channel_handle_t chan = NULL;
|
||||
mcpwm_capture_channel_config_t cfg = {
|
||||
.gpio_num = gpio,
|
||||
.prescale = prescale,
|
||||
.flags.pos_edge = pos_edge,
|
||||
.flags.neg_edge = neg_edge,
|
||||
};
|
||||
test_prescale_ctx_t ctx = {};
|
||||
mcpwm_capture_event_callbacks_t cbs = {.on_cap = test_prescale_cap_cb};
|
||||
|
||||
// Always start low so every mode drives the same rise-then-fall sequence.
|
||||
gpio_set_level(gpio, 0);
|
||||
|
||||
TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cfg, &chan));
|
||||
TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(chan, &cbs, &ctx));
|
||||
TEST_ESP_OK(mcpwm_capture_channel_enable(chan));
|
||||
|
||||
printf("prescale=%" PRIu32 " mode=%s cycles=%" PRIu32 " expect_caps=%" PRIu32 "\n",
|
||||
prescale, both ? "both" : (pos_edge ? "pos" : "neg"), cycles, expect);
|
||||
|
||||
uint32_t rise_caps = 0;
|
||||
uint32_t fall_caps = 0;
|
||||
int first_cap_cycle = -1;
|
||||
const char *first_cap_via = NULL;
|
||||
|
||||
for (uint32_t c = 0; c < cycles; c++) {
|
||||
mcpwm_capture_edge_t edge;
|
||||
if (test_prescale_step(gpio, 1, &ctx, c, &edge)) {
|
||||
const char *name = (edge == MCPWM_CAP_EDGE_POS) ? "R" : "F";
|
||||
printf(" cycle%-2" PRIu32 " rise -> %s\n", c, name);
|
||||
if (edge == MCPWM_CAP_EDGE_POS) {
|
||||
rise_caps++;
|
||||
} else {
|
||||
fall_caps++;
|
||||
}
|
||||
if (first_cap_cycle < 0) {
|
||||
first_cap_cycle = (int)c;
|
||||
first_cap_via = "rise";
|
||||
}
|
||||
}
|
||||
if (test_prescale_step(gpio, 0, &ctx, c, &edge)) {
|
||||
const char *name = (edge == MCPWM_CAP_EDGE_POS) ? "R" : "F";
|
||||
printf(" cycle%-2" PRIu32 " fall -> %s\n", c, name);
|
||||
if (edge == MCPWM_CAP_EDGE_POS) {
|
||||
rise_caps++;
|
||||
} else {
|
||||
fall_caps++;
|
||||
}
|
||||
if (first_cap_cycle < 0) {
|
||||
first_cap_cycle = (int)c;
|
||||
first_cap_via = "fall";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf(" caps=%" PRIu32 " (R-reported=%" PRIu32 " F-reported=%" PRIu32 ") first@cycle%d via %s\n",
|
||||
ctx.count, rise_caps, fall_caps, first_cap_cycle, first_cap_via ? first_cap_via : "?");
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(expect, ctx.count);
|
||||
// After a clean timer+channel recreate, cadence and first-cycle phase are both fixed.
|
||||
const uint32_t same_gap = (prescale <= 1) ? 1 : (both ? (prescale / 2) : prescale);
|
||||
if (both && (prescale <= 1)) {
|
||||
for (uint32_t i = 2; i < ctx.count; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT32(1, ctx.cycles[i] - ctx.cycles[i - 2]);
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 1; i < ctx.count; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT32(same_gap, ctx.cycles[i] - ctx.cycles[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (pos_edge && !neg_edge) {
|
||||
// Rising-only: always reports R, fires on rising GPIO steps.
|
||||
// After clean reset: first at cycle (prescale/2 - 1) when prescale > 1.
|
||||
TEST_ASSERT_EQUAL_UINT32(expect, rise_caps);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, fall_caps);
|
||||
TEST_ASSERT_NOT_NULL(first_cap_via);
|
||||
TEST_ASSERT_EQUAL_STRING("rise", first_cap_via);
|
||||
TEST_ASSERT_EQUAL_INT((prescale <= 1) ? 0 : (int)(prescale / 2 - 1), first_cap_cycle);
|
||||
} else if (neg_edge && !pos_edge) {
|
||||
// Falling-only path always reports F (cap_edge neg).
|
||||
// Bypass: fires on GPIO falling steps at cycle 0.
|
||||
// Prescale > 1: fires on GPIO rising steps, first at cycle (prescale - 1).
|
||||
TEST_ASSERT_EQUAL_UINT32(expect, fall_caps);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, rise_caps);
|
||||
TEST_ASSERT_NOT_NULL(first_cap_via);
|
||||
if (prescale <= 1) {
|
||||
TEST_ASSERT_EQUAL_STRING("fall", first_cap_via);
|
||||
TEST_ASSERT_EQUAL_INT(0, first_cap_cycle);
|
||||
} else {
|
||||
TEST_ASSERT_EQUAL_STRING("rise", first_cap_via);
|
||||
TEST_ASSERT_EQUAL_INT((int)(prescale - 1), first_cap_cycle);
|
||||
}
|
||||
} else {
|
||||
// Both edges: equal R/F counts. Bypass maps to real rise/fall.
|
||||
// Prescale > 1: rising steps only, alternates R/F from R; first like rising-only.
|
||||
TEST_ASSERT_EQUAL_UINT32(TEST_PRESCALE_GROUPS, rise_caps);
|
||||
TEST_ASSERT_EQUAL_UINT32(TEST_PRESCALE_GROUPS, fall_caps);
|
||||
TEST_ASSERT_NOT_NULL(first_cap_via);
|
||||
TEST_ASSERT_EQUAL_STRING("rise", first_cap_via);
|
||||
TEST_ASSERT_EQUAL(MCPWM_CAP_EDGE_POS, ctx.edges[0]);
|
||||
TEST_ASSERT_EQUAL_INT((prescale <= 1) ? 0 : (int)(prescale / 2 - 1), first_cap_cycle);
|
||||
}
|
||||
|
||||
TEST_ESP_OK(mcpwm_capture_channel_disable(chan));
|
||||
TEST_ESP_OK(mcpwm_del_capture_channel(chan));
|
||||
TEST_ESP_OK(mcpwm_capture_timer_stop(cap_timer));
|
||||
TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
|
||||
TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_capture_prescale_ratio", "[mcpwm]")
|
||||
{
|
||||
const int gpio = TEST_CAP_GPIO;
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT,
|
||||
.pin_bit_mask = BIT(gpio),
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&io_conf));
|
||||
gpio_set_level(gpio, 0);
|
||||
|
||||
// Odd API prescale must be rejected (uses a throwaway timer).
|
||||
mcpwm_cap_timer_handle_t cap_timer = NULL;
|
||||
mcpwm_capture_timer_config_t cap_cfg = {
|
||||
.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_capture_timer(&cap_cfg, &cap_timer));
|
||||
mcpwm_cap_channel_handle_t bad = NULL;
|
||||
mcpwm_capture_channel_config_t bad_cfg = {
|
||||
.gpio_num = gpio, .prescale = 3, .flags.pos_edge = true,
|
||||
};
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_new_capture_channel(cap_timer, &bad_cfg, &bad));
|
||||
TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
|
||||
|
||||
const uint32_t expected_prescales[] = {1, 2, 4, 16};
|
||||
for (size_t i = 0; i < sizeof(expected_prescales) / sizeof(expected_prescales[0]); i++) {
|
||||
printf("------------------------------------------------\r\n");
|
||||
test_prescale_check(gpio, expected_prescales[i], true, false);
|
||||
test_prescale_check(gpio, expected_prescales[i], false, true);
|
||||
test_prescale_check(gpio, expected_prescales[i], true, true);
|
||||
}
|
||||
|
||||
TEST_ESP_OK(gpio_reset_pin(gpio));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -1604,16 +1604,18 @@ static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the prescale of the input capture signal
|
||||
* @brief Set capture input prescale (same-edge ratio)
|
||||
*
|
||||
* @note Hardware field N = 0 means bypass (ratio 1); N >= 1 means same-edge ratio = 2 * N.
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param channel Channel ID, index from 0 to 2
|
||||
* @param prescale Prescale value
|
||||
* @param prescale Desired same-edge ratio: 1 (bypass) or even
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
|
||||
{
|
||||
HAL_ASSERT(prescale > 0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale / 2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////Deprecated Functions//////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1643,16 +1643,18 @@ static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the prescale of the input capture signal
|
||||
* @brief Set capture input prescale (same-edge ratio)
|
||||
*
|
||||
* @note Hardware field N = 0 means bypass (ratio 1); N >= 1 means same-edge ratio = 2 * N.
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param channel Channel ID, index from 0 to 2
|
||||
* @param prescale Prescale value
|
||||
* @param prescale Desired same-edge ratio: 1 (bypass) or even
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
|
||||
{
|
||||
HAL_ASSERT(prescale > 0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale / 2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1621,16 +1621,18 @@ static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the prescale of the input capture signal
|
||||
* @brief Set capture input prescale (same-edge ratio)
|
||||
*
|
||||
* @note Hardware field N = 0 means bypass (ratio 1); N >= 1 means same-edge ratio = 2 * N.
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param channel Channel ID, index from 0 to 2
|
||||
* @param prescale Prescale value
|
||||
* @param prescale Desired same-edge ratio: 1 (bypass) or even
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
|
||||
{
|
||||
HAL_ASSERT(prescale > 0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale / 2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1619,16 +1619,18 @@ static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the prescale of the input capture signal
|
||||
* @brief Set capture input prescale (same-edge ratio)
|
||||
*
|
||||
* @note Hardware field N = 0 means bypass (ratio 1); N >= 1 means same-edge ratio = 2 * N.
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param channel Channel ID, index from 0 to 2
|
||||
* @param prescale Prescale value
|
||||
* @param prescale Desired same-edge ratio: 1 (bypass) or even
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
|
||||
{
|
||||
HAL_ASSERT(prescale > 0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale / 2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1698,16 +1698,18 @@ static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the prescale of the input capture signal
|
||||
* @brief Set capture input prescale (same-edge ratio)
|
||||
*
|
||||
* @note Hardware field N = 0 means bypass (ratio 1); N >= 1 means same-edge ratio = 2 * N.
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param channel Channel ID, index from 0 to 2
|
||||
* @param prescale Prescale value
|
||||
* @param prescale Desired same-edge ratio: 1 (bypass) or even
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
|
||||
{
|
||||
HAL_ASSERT(prescale > 0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale / 2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -1612,16 +1612,18 @@ static inline mcpwm_capture_edge_t mcpwm_ll_capture_get_edge(mcpwm_dev_t *mcpwm,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the prescale of the input capture signal
|
||||
* @brief Set capture input prescale (same-edge ratio)
|
||||
*
|
||||
* @note Hardware field N = 0 means bypass (ratio 1); N >= 1 means same-edge ratio = 2 * N.
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param channel Channel ID, index from 0 to 2
|
||||
* @param prescale Prescale value
|
||||
* @param prescale Desired same-edge ratio: 1 (bypass) or even
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
|
||||
{
|
||||
HAL_ASSERT(prescale > 0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale / 2);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////Deprecated Functions//////////////////////////////////////////////////////////
|
||||
|
||||
74
docs/_static/mcpwm/capture_prescale_both.svg
vendored
Normal file
74
docs/_static/mcpwm/capture_prescale_both.svg
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 440" font-family="'DejaVu Sans Mono', 'Consolas', 'Liberation Mono', monospace">
|
||||
<defs>
|
||||
<marker id="arr" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||||
<polygon points="0,0 8,3 0,6" fill="#555"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="700" height="440" fill="#ffffff" rx="8"/>
|
||||
<text x="350" y="24" text-anchor="middle" font-size="13" fill="#333" font-weight="700">Both edges</text>
|
||||
<text x="350" y="42" text-anchor="middle" font-size="10" fill="#666">API prescale = same-edge ratio</text>
|
||||
|
||||
<text x="20" y="68" font-size="12" fill="#333" font-weight="700">A. prescale = 1 (bypass)</text>
|
||||
<g transform="translate(80, 78)">
|
||||
<text x="-10" y="36" text-anchor="end" font-size="11" fill="#1e88e5" font-weight="600">input</text>
|
||||
<polyline fill="none" stroke="#1e88e5" stroke-width="2"
|
||||
points="0,40 0,12 35,12 35,40 70,40 70,12 105,12 105,40 140,40 140,12 175,12 175,40 210,40"/>
|
||||
<g fill="#e53935"><circle cx="0" cy="12" r="3.5"/><circle cx="70" cy="12" r="3.5"/><circle cx="140" cy="12" r="3.5"/></g>
|
||||
<g fill="#fb8c00"><rect x="31" y="8" width="8" height="8"/><rect x="101" y="8" width="8" height="8"/><rect x="171" y="8" width="8" height="8"/></g>
|
||||
<text x="-10" y="100" text-anchor="end" font-size="11" fill="#333" font-weight="600">capture</text>
|
||||
<line x1="0" y1="92" x2="210" y2="92" stroke="#999" stroke-width="1.5"/>
|
||||
<line x1="0" y1="12" x2="0" y2="92" stroke="#e53935" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="35" y1="40" x2="35" y2="92" stroke="#fb8c00" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="70" y1="12" x2="70" y2="92" stroke="#e53935" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="105" y1="40" x2="105" y2="92" stroke="#fb8c00" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<polyline points="0,92 0,72 12,72 12,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="35,92 35,72 47,72 47,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<polyline points="70,92 70,72 82,72 82,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="105,92 105,72 117,72 117,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<text x="6" y="66" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="41" y="66" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="76" y="66" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="111" y="66" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="250" y="36" font-size="10" fill="#e53935" font-weight="600">R = GPIO rising</text>
|
||||
<text x="250" y="54" font-size="10" fill="#fb8c00" font-weight="600">F = GPIO falling</text>
|
||||
</g>
|
||||
|
||||
<text x="20" y="228" font-size="12" fill="#333" font-weight="700">B. prescale = 4</text>
|
||||
<g transform="translate(80, 250)">
|
||||
<text x="-10" y="36" text-anchor="end" font-size="11" fill="#1e88e5" font-weight="600">input</text>
|
||||
<polyline fill="none" stroke="#1e88e5" stroke-width="2"
|
||||
points="0,40 0,12 35,12 35,40 70,40 70,12 105,12 105,40 140,40 140,12 175,12 175,40 210,40 210,12 245,12 245,40 280,40 280,12 315,12 315,40 350,40 350,12 385,12 385,40 420,40 420,12 455,12 455,40 490,40 490,12"/>
|
||||
<!-- first at cycle 1, then every 2: 1(R),3(F),5(R),7(F) -->
|
||||
<g fill="#1e88e5"><circle cx="70" cy="12" r="3.5"/><circle cx="210" cy="12" r="3.5"/><circle cx="350" cy="12" r="3.5"/><circle cx="490" cy="12" r="3.5"/></g>
|
||||
<g fill="#bbb"><circle cx="0" cy="12" r="3"/><circle cx="140" cy="12" r="3"/><circle cx="280" cy="12" r="3"/><circle cx="420" cy="12" r="3"/></g>
|
||||
<g fill="#ccc"><rect x="31" y="8" width="8" height="8"/><rect x="101" y="8" width="8" height="8"/><rect x="171" y="8" width="8" height="8"/><rect x="241" y="8" width="8" height="8"/><rect x="311" y="8" width="8" height="8"/><rect x="381" y="8" width="8" height="8"/><rect x="451" y="8" width="8" height="8"/></g>
|
||||
<text x="70" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 1</text>
|
||||
<text x="210" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 3</text>
|
||||
<text x="350" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 5</text>
|
||||
<text x="490" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 7</text>
|
||||
|
||||
<text x="-10" y="100" text-anchor="end" font-size="11" fill="#333" font-weight="600">capture</text>
|
||||
<line x1="0" y1="92" x2="490" y2="92" stroke="#999" stroke-width="1.5"/>
|
||||
<line x1="70" y1="12" x2="70" y2="92" stroke="#e53935" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="210" y1="12" x2="210" y2="92" stroke="#fb8c00" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="350" y1="12" x2="350" y2="92" stroke="#e53935" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="490" y1="12" x2="490" y2="92" stroke="#fb8c00" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<polyline points="70,92 70,70 82,70 82,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="210,92 210,70 222,70 222,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<polyline points="350,92 350,70 362,70 362,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="490,92 490,70 502,70 502,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<text x="76" y="64" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="216" y="64" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="356" y="64" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="496" y="64" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
|
||||
<line x1="70" y1="110" x2="70" y2="120" stroke="#666"/><line x1="210" y1="110" x2="210" y2="120" stroke="#666"/>
|
||||
<line x1="70" y1="115" x2="210" y2="115" stroke="#666" stroke-width="1.5" marker-end="url(#arr)"/>
|
||||
<text x="140" y="134" text-anchor="middle" font-size="10" fill="#666" font-weight="600">adj = 2 x T = (prescale/2) x T</text>
|
||||
|
||||
<line x1="70" y1="144" x2="70" y2="154" stroke="#e53935"/><line x1="350" y1="144" x2="350" y2="154" stroke="#e53935"/>
|
||||
<line x1="70" y1="149" x2="350" y2="149" stroke="#e53935" stroke-width="1.5" marker-end="url(#arr)"/>
|
||||
<text x="210" y="168" text-anchor="middle" font-size="11" fill="#e53935" font-weight="600">R-to-R = 4 x T = prescale x T</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
61
docs/_static/mcpwm/capture_prescale_falling.svg
vendored
Normal file
61
docs/_static/mcpwm/capture_prescale_falling.svg
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 420" font-family="'DejaVu Sans Mono', 'Consolas', 'Liberation Mono', monospace">
|
||||
<defs>
|
||||
<marker id="arr" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||||
<polygon points="0,0 8,3 0,6" fill="#555"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="700" height="420" fill="#ffffff" rx="8"/>
|
||||
<text x="350" y="24" text-anchor="middle" font-size="13" fill="#333" font-weight="700">Falling-edge only</text>
|
||||
<text x="350" y="42" text-anchor="middle" font-size="10" fill="#666">API prescale = same-edge ratio</text>
|
||||
|
||||
<text x="20" y="68" font-size="12" fill="#333" font-weight="700">A. prescale = 1 (bypass)</text>
|
||||
<g transform="translate(80, 78)">
|
||||
<text x="-10" y="36" text-anchor="end" font-size="11" fill="#1e88e5" font-weight="600">input</text>
|
||||
<polyline fill="none" stroke="#1e88e5" stroke-width="2"
|
||||
points="0,40 0,12 35,12 35,40 70,40 70,12 105,12 105,40 140,40 140,12 175,12 175,40 210,40"/>
|
||||
<g fill="#ccc"><circle cx="0" cy="12" r="3"/><circle cx="70" cy="12" r="3"/><circle cx="140" cy="12" r="3"/></g>
|
||||
<g fill="#fb8c00"><rect x="31" y="8" width="8" height="8"/><rect x="101" y="8" width="8" height="8"/><rect x="171" y="8" width="8" height="8"/></g>
|
||||
<text x="-10" y="100" text-anchor="end" font-size="11" fill="#fb8c00" font-weight="600">capture</text>
|
||||
<line x1="0" y1="92" x2="210" y2="92" stroke="#fb8c00" stroke-width="1.5"/>
|
||||
<line x1="35" y1="40" x2="35" y2="92" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="105" y1="40" x2="105" y2="92" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="175" y1="40" x2="175" y2="92" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<polyline points="35,92 35,72 47,72 47,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<polyline points="105,92 105,72 117,72 117,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<polyline points="175,92 175,72 187,72 187,92" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<text x="41" y="66" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="111" y="66" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="181" y="66" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="250" y="40" font-size="10" fill="#555">Every falling edge -> F</text>
|
||||
<text x="250" y="58" font-size="10" fill="#888">Rising edges ignored</text>
|
||||
</g>
|
||||
|
||||
<text x="20" y="228" font-size="12" fill="#333" font-weight="700">B. prescale = 4</text>
|
||||
<g transform="translate(80, 250)">
|
||||
<text x="-10" y="36" text-anchor="end" font-size="11" fill="#1e88e5" font-weight="600">input</text>
|
||||
<polyline fill="none" stroke="#1e88e5" stroke-width="2"
|
||||
points="0,40 0,12 35,12 35,40 70,40 70,12 105,12 105,40 140,40 140,12 175,12 175,40 210,40 210,12 245,12 245,40 280,40 280,12 315,12 315,40 350,40 350,12 385,12 385,40 420,40 420,12 455,12 455,40 490,40 490,12"/>
|
||||
<!-- first at cycle 3, then every 4: cycle 3, 7 -->
|
||||
<g fill="#1e88e5"><circle cx="210" cy="12" r="3.5"/><circle cx="490" cy="12" r="3.5"/></g>
|
||||
<g fill="#bbb"><circle cx="0" cy="12" r="3"/><circle cx="70" cy="12" r="3"/><circle cx="140" cy="12" r="3"/><circle cx="280" cy="12" r="3"/><circle cx="350" cy="12" r="3"/><circle cx="420" cy="12" r="3"/></g>
|
||||
<g fill="#ccc"><rect x="31" y="8" width="8" height="8"/><rect x="101" y="8" width="8" height="8"/><rect x="171" y="8" width="8" height="8"/><rect x="241" y="8" width="8" height="8"/><rect x="311" y="8" width="8" height="8"/><rect x="381" y="8" width="8" height="8"/><rect x="451" y="8" width="8" height="8"/></g>
|
||||
<text x="210" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 3</text>
|
||||
<text x="490" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 7</text>
|
||||
<line x1="0" y1="52" x2="70" y2="52" stroke="#bbb" stroke-width="1"/>
|
||||
<line x1="0" y1="48" x2="0" y2="56" stroke="#bbb"/><line x1="70" y1="48" x2="70" y2="56" stroke="#bbb"/>
|
||||
<text x="35" y="68" text-anchor="middle" font-size="10" fill="#888">T</text>
|
||||
<text x="-10" y="108" text-anchor="end" font-size="11" fill="#fb8c00" font-weight="600">capture</text>
|
||||
<line x1="0" y1="100" x2="490" y2="100" stroke="#fb8c00" stroke-width="1.5"/>
|
||||
<line x1="210" y1="12" x2="210" y2="100" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="490" y1="12" x2="490" y2="100" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<polyline points="210,100 210,80 222,80 222,100" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<polyline points="490,100 490,80 502,80 502,100" fill="none" stroke="#fb8c00" stroke-width="2"/>
|
||||
<text x="216" y="74" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="496" y="74" text-anchor="middle" font-size="10" fill="#fb8c00" font-weight="700">F</text>
|
||||
<text x="350" y="90" text-anchor="middle" font-size="10" fill="#555">first = prescale - 1, then every 4</text>
|
||||
<line x1="210" y1="118" x2="210" y2="130" stroke="#333"/><line x1="490" y1="118" x2="490" y2="130" stroke="#333"/>
|
||||
<line x1="210" y1="124" x2="490" y2="124" stroke="#333" stroke-width="1.5" marker-end="url(#arr)"/>
|
||||
<text x="350" y="146" text-anchor="middle" font-size="11" fill="#333" font-weight="600">same-edge = 4 x T = prescale x T</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
60
docs/_static/mcpwm/capture_prescale_rising.svg
vendored
Normal file
60
docs/_static/mcpwm/capture_prescale_rising.svg
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 400" font-family="'DejaVu Sans Mono', 'Consolas', 'Liberation Mono', monospace">
|
||||
<defs>
|
||||
<marker id="arr" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||||
<polygon points="0,0 8,3 0,6" fill="#555"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="700" height="400" fill="#ffffff" rx="8"/>
|
||||
<text x="350" y="24" text-anchor="middle" font-size="13" fill="#333" font-weight="700">Rising-edge only</text>
|
||||
<text x="350" y="42" text-anchor="middle" font-size="10" fill="#666">API prescale = same-edge ratio</text>
|
||||
|
||||
<text x="20" y="68" font-size="12" fill="#333" font-weight="700">A. prescale = 1 (bypass)</text>
|
||||
<g transform="translate(80, 78)">
|
||||
<text x="-10" y="36" text-anchor="end" font-size="11" fill="#1e88e5" font-weight="600">input</text>
|
||||
<polyline fill="none" stroke="#1e88e5" stroke-width="2"
|
||||
points="0,40 0,12 35,12 35,40 70,40 70,12 105,12 105,40 140,40 140,12 175,12 175,40 210,40"/>
|
||||
<g fill="#1e88e5"><circle cx="0" cy="12" r="3.5"/><circle cx="70" cy="12" r="3.5"/><circle cx="140" cy="12" r="3.5"/></g>
|
||||
<g fill="#ccc"><rect x="31" y="8" width="8" height="8"/><rect x="101" y="8" width="8" height="8"/><rect x="171" y="8" width="8" height="8"/></g>
|
||||
<text x="-10" y="100" text-anchor="end" font-size="11" fill="#e53935" font-weight="600">capture</text>
|
||||
<line x1="0" y1="92" x2="210" y2="92" stroke="#e53935" stroke-width="1.5"/>
|
||||
<line x1="0" y1="12" x2="0" y2="92" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="70" y1="12" x2="70" y2="92" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="140" y1="12" x2="140" y2="92" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<polyline points="0,92 0,72 12,72 12,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="70,92 70,72 82,72 82,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="140,92 140,72 152,72 152,92" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<text x="6" y="66" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="76" y="66" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="146" y="66" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="250" y="40" font-size="10" fill="#555">Every rising edge -> R</text>
|
||||
<text x="250" y="58" font-size="10" fill="#888">Falling edges ignored</text>
|
||||
</g>
|
||||
|
||||
<text x="20" y="228" font-size="12" fill="#333" font-weight="700">B. prescale = 4</text>
|
||||
<g transform="translate(80, 250)">
|
||||
<text x="-10" y="36" text-anchor="end" font-size="11" fill="#1e88e5" font-weight="600">input</text>
|
||||
<polyline fill="none" stroke="#1e88e5" stroke-width="2"
|
||||
points="0,40 0,12 35,12 35,40 70,40 70,12 105,12 105,40 140,40 140,12 175,12 175,40 210,40 210,12 245,12 245,40 280,40 280,12 315,12 315,40 350,40 350,12 385,12 385,40 420,40 420,12"/>
|
||||
<!-- first at cycle 1, then every 4: cycle 1, 5 -->
|
||||
<g fill="#bbb"><circle cx="0" cy="12" r="3"/><circle cx="140" cy="12" r="3"/><circle cx="210" cy="12" r="3"/><circle cx="280" cy="12" r="3"/><circle cx="420" cy="12" r="3"/></g>
|
||||
<g fill="#1e88e5"><circle cx="70" cy="12" r="3.5"/><circle cx="350" cy="12" r="3.5"/></g>
|
||||
<text x="70" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 1</text>
|
||||
<text x="350" y="-4" text-anchor="middle" font-size="9" fill="#1e88e5" font-weight="700">cycle 5</text>
|
||||
<line x1="0" y1="52" x2="70" y2="52" stroke="#bbb" stroke-width="1"/>
|
||||
<line x1="0" y1="48" x2="0" y2="56" stroke="#bbb"/><line x1="70" y1="48" x2="70" y2="56" stroke="#bbb"/>
|
||||
<text x="35" y="68" text-anchor="middle" font-size="10" fill="#888">T</text>
|
||||
<text x="-10" y="108" text-anchor="end" font-size="11" fill="#e53935" font-weight="600">capture</text>
|
||||
<line x1="0" y1="100" x2="420" y2="100" stroke="#e53935" stroke-width="1.5"/>
|
||||
<line x1="70" y1="12" x2="70" y2="100" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<line x1="350" y1="12" x2="350" y2="100" stroke="#ccc" stroke-width="1" stroke-dasharray="3,3"/>
|
||||
<polyline points="70,100 70,80 82,80 82,100" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<polyline points="350,100 350,80 362,80 362,100" fill="none" stroke="#e53935" stroke-width="2"/>
|
||||
<text x="76" y="74" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="356" y="74" text-anchor="middle" font-size="10" fill="#e53935" font-weight="700">R</text>
|
||||
<text x="210" y="90" text-anchor="middle" font-size="10" fill="#555">first = prescale/2 - 1, then every 4</text>
|
||||
<line x1="70" y1="118" x2="70" y2="130" stroke="#333"/><line x1="350" y1="118" x2="350" y2="130" stroke="#333"/>
|
||||
<line x1="70" y1="124" x2="350" y2="124" stroke="#333" stroke-width="1.5" marker-end="url(#arr)"/>
|
||||
<text x="210" y="146" text-anchor="middle" font-size="11" fill="#333" font-weight="600">same-edge = 4 x T = prescale x T</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -936,6 +936,49 @@ The parameter ``user_data`` of :cpp:func:`mcpwm_capture_channel_register_event_c
|
||||
|
||||
This function will lazy install interrupt service for the MCPWM capture channel, whereas the service can only be removed in :cpp:type:`mcpwm_del_capture_channel`.
|
||||
|
||||
Input Prescale
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The capture channel processes the input in a **fixed, serial** order:
|
||||
|
||||
1. **First** divide the GPIO waveform by ``prescale`` (``0`` or ``1`` means bypass);
|
||||
2. **Then** use ``pos_edge``/``neg_edge`` to decide which post-prescale events are reported to software.
|
||||
|
||||
So hardware does **not** first filter physical GPIO edges by polarity and only then divide them. With ``prescale > 1``:
|
||||
|
||||
- The :cpp:member:`cap_edge <mcpwm_capture_event_data_t::cap_edge>` seen in the callback may not match the physical GPIO edge.
|
||||
- Adjacent opposite-edge gaps are **not pulse width**, and **the true duty cycle cannot be recovered** from them.
|
||||
|
||||
Always compute period or frequency from timestamps of the same reported edge type.
|
||||
|
||||
.. note::
|
||||
|
||||
Keep ``prescale = 1`` and capture both edges when measuring pulse width or duty cycle. Raise ``prescale`` only when you need to reduce the capture rate for fast inputs and you only care about period or frequency.
|
||||
|
||||
The figures below show how ``prescale`` affects capture timing for rising-only, falling-only, and both-edge modes.
|
||||
|
||||
.. figure:: /../_static/mcpwm/capture_prescale_rising.svg
|
||||
:align: center
|
||||
:alt: Rising-edge only capture with prescale bypass and prescale 4.
|
||||
|
||||
Rising-edge only. With ``prescale = 1`` every rising edge captures as ``R``. With ``prescale > 1``, the first capture is at cycle ``prescale / 2 - 1``, then every ``prescale``-th rising edge.
|
||||
|
||||
.. figure:: /../_static/mcpwm/capture_prescale_falling.svg
|
||||
:align: center
|
||||
:alt: Falling-edge only capture with prescale bypass and prescale 4.
|
||||
|
||||
Falling-edge only. With ``prescale = 1`` every falling edge captures as ``F``. With ``prescale > 1``, GPIO falling edges do not directly produce captures; events land on rising steps while ``cap_edge`` still reports ``F``.
|
||||
|
||||
.. figure:: /../_static/mcpwm/capture_prescale_both.svg
|
||||
:align: center
|
||||
:alt: Both-edge capture with prescale bypass and prescale 4.
|
||||
|
||||
Both-edge capture. With ``prescale = 1``, ``R``/``F`` match the physical pin edges. With ``prescale > 1``, captures fire on rising pin steps only, while reported ``R``/``F`` alternate after prescaling.
|
||||
|
||||
.. warning::
|
||||
|
||||
Do not infer the physical GPIO transition from :cpp:member:`mcpwm_capture_event_data_t::cap_edge` when ``prescale > 1``, and do not treat adjacent opposite-edge gaps as pulse width.
|
||||
|
||||
Enable and Disable Capture Channel
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -936,6 +936,49 @@ MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须
|
||||
|
||||
此函数会延迟安装 MCPWM 捕获的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_capture_channel` 移除。
|
||||
|
||||
输入预分频
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
捕获通道内部按**固定顺序**串行处理输入:
|
||||
|
||||
1. 先用 ``prescale`` 对 GPIO 波形做分频(``0`` 或 ``1`` 表示 bypass);
|
||||
2. 再根据 ``pos_edge``/``neg_edge`` 决定哪些分频后的事件上报给软件。
|
||||
|
||||
因此,硬件并不是先按物理 GPIO 边沿极性过滤,再对这些边沿做分频。对于 ``prescale > 1``:
|
||||
|
||||
- 回调里看到的 :cpp:member:`cap_edge <mcpwm_capture_event_data_t::cap_edge>` 可能和 GPIO 的真实物理边沿不一致。
|
||||
- 相邻异沿之间的时间差**不代表脉宽**,并且**无法据此还原真实占空比**。
|
||||
|
||||
计算周期或频率时,请始终使用相同上报边沿类型(同沿)的两次时间戳。
|
||||
|
||||
.. note::
|
||||
|
||||
测量脉宽或占空比时,请保持 ``prescale = 1`` 并同时捕获双边沿。只有在输入过快、你只关心周期或频率时,才建议提高 ``prescale`` 来降低捕获速率。
|
||||
|
||||
下图说明 ``prescale`` 对仅上升沿、仅下降沿和双边沿捕获时序的影响。
|
||||
|
||||
.. figure:: /../_static/mcpwm/capture_prescale_rising.svg
|
||||
:align: center
|
||||
:alt: 仅上升沿捕获:prescale bypass 与 prescale 4。
|
||||
|
||||
仅上升沿。``prescale = 1`` 时,每个上升沿都会捕获为 ``R``。``prescale > 1`` 时,首次捕获出现在 cycle ``prescale / 2 - 1``,之后每隔 ``prescale`` 个上升沿捕获一次。
|
||||
|
||||
.. figure:: /../_static/mcpwm/capture_prescale_falling.svg
|
||||
:align: center
|
||||
:alt: 仅下降沿捕获:prescale bypass 与 prescale 4。
|
||||
|
||||
仅下降沿。``prescale = 1`` 时,每个下降沿都会捕获为 ``F``。``prescale > 1`` 时,GPIO 的下降沿不会直接触发捕获;事件会落在上升沿步骤上,但 ``cap_edge`` 仍然上报 ``F``。
|
||||
|
||||
.. figure:: /../_static/mcpwm/capture_prescale_both.svg
|
||||
:align: center
|
||||
:alt: 双边沿捕获:prescale bypass 与 prescale 4。
|
||||
|
||||
双边沿。``prescale = 1`` 时,``R``/``F`` 与引脚真实边沿一致。``prescale > 1`` 时,捕获只会落在上升沿步骤上,而分频后的上报事件在 ``R``/``F`` 之间交替。
|
||||
|
||||
.. warning::
|
||||
|
||||
当 ``prescale > 1`` 时,不要根据 :cpp:member:`mcpwm_capture_event_data_t::cap_edge` 去推断 GPIO 的真实跳变方向,也不要把相邻异沿间隔当作脉宽。
|
||||
|
||||
启用或禁用捕获通道
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
Reference in New Issue
Block a user