forked from espressif/esp-idf
example: update MCPWM sync example with new driver API
This commit is contained in:
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mcpwm_sync_example)
|
||||
project(mcpwm_sync)
|
88
examples/peripherals/mcpwm/mcpwm_sync/README.md
Normal file
88
examples/peripherals/mcpwm/mcpwm_sync/README.md
Normal file
@@ -0,0 +1,88 @@
|
||||
| Supported Targets | ESP32 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- |
|
||||
|
||||
# MCPWM Sync Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
MCPWM timers can't be started together because you have to call **mcpwm_timer_start_stop** function timer by timer, so the generators driven by them are not in sync with each other. But there're several ways to force these timers jump to the same point by setting sync phase for timers and then wait for a proper sync event to happen.
|
||||
|
||||
This example illustrates how to generate three PWMs that are in perfect synchronization.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with any Espressif SoC which features MCPWM peripheral (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
|
||||
It is recommended to have an oscilloscope or logic analyzer to view the generated PWM waveforms.
|
||||
|
||||
Connection :
|
||||
|
||||
```
|
||||
ESP Board oscilloscope / logic analyzer
|
||||
+--------------------------+ +----------------------------+
|
||||
| | | |
|
||||
| EXAMPLE_GEN_GPIO0 +-----------------+ channelA |
|
||||
| | | |
|
||||
| EXAMPLE_GEN_GPIO1 +-----------------+ channelB |
|
||||
| | | |
|
||||
| EXAMPLE_GEN_GPIO2 +-----------------+ channelC |
|
||||
| | | |
|
||||
| GND +-----------------+ GND |
|
||||
| | | |
|
||||
+--------------------------+ +----------------------------+
|
||||
```
|
||||
|
||||
Above used GPIO numbers (e.g. `EXAMPLE_GEN_GPIO0`) can be changed in [the source file](main/mcpwm_sync_example_main.c).
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
You can select the way to synchronize the MCPWM timers in the menu: `Example Configuration` -> `Where the sync event is generated from`.
|
||||
|
||||
* GPIO
|
||||
* This approach will consume a GPIO, where a configurable pulse on the GPIO is treated as the sync event. And the sync event is routed to each MCPWM timers.
|
||||
* Timer TEZ
|
||||
* This approach won't consume any GPIO, the sync even is generated by a main timer, and then routed to other MCPWM timers. The drawback of this approach is, the main timer will have a tiny phase shift to other two timers.
|
||||
* Software (optional)
|
||||
* This approach won't consume any GPIO as well and also doesn't have the drawback in the `Timer TEZ` approach. The main timer is sync by software, and it will propagate the sync event to other timers.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (305) example: Create timers
|
||||
I (305) example: Create operators
|
||||
I (305) example: Connect timers and operators with each other
|
||||
I (315) example: Create comparators
|
||||
I (315) example: Create generators
|
||||
I (325) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (335) gpio: GPIO[2]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (345) gpio: GPIO[4]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (355) example: Set generator actions on timer and compare event
|
||||
I (355) example: Start timers one by one, so they are not synced
|
||||
I (495) example: Force the output level to low, timer still running
|
||||
I (495) example: Setup sync strategy
|
||||
I (495) example: Create GPIO sync source
|
||||
I (495) gpio: GPIO[5]| InputEn: 1| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 1| Intr:0
|
||||
I (505) example: Set timers to sync on the GPIO
|
||||
I (505) example: Trigger a pulse on the GPIO as a sync event
|
||||
I (515) example: Now the output PWMs should in sync
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "mcpwm_sync_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
20
examples/peripherals/mcpwm/mcpwm_sync/main/Kconfig.projbuild
Normal file
20
examples/peripherals/mcpwm/mcpwm_sync/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,20 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_SYNC_FROM
|
||||
prompt "Where the sync event is generated from"
|
||||
default EXAMPLE_SYNC_FROM_GPIO
|
||||
help
|
||||
Select MCPWM sync source.
|
||||
|
||||
config EXAMPLE_SYNC_FROM_GPIO
|
||||
bool "GPIO"
|
||||
|
||||
config EXAMPLE_SYNC_FROM_TEZ
|
||||
bool "Timer TEZ"
|
||||
|
||||
config EXAMPLE_SYNC_FROM_SOFT
|
||||
bool "Software"
|
||||
depends on SOC_MCPWM_SWSYNC_CAN_PROPAGATE
|
||||
endchoice
|
||||
|
||||
endmenu
|
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/mcpwm_prelude.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
const static char *TAG = "example";
|
||||
|
||||
#define EXAMPLE_TIMER_RESOLUTION_HZ 1000000 // 1MHz, 1us per tick
|
||||
#define EXAMPLE_TIMER_PERIOD 1000 // 1000 ticks, 1ms
|
||||
#define EXAMPLE_GEN_GPIO0 0
|
||||
#define EXAMPLE_GEN_GPIO1 2
|
||||
#define EXAMPLE_GEN_GPIO2 4
|
||||
#define EXAMPLE_SYNC_GPIO 5
|
||||
|
||||
#if CONFIG_EXAMPLE_SYNC_FROM_GPIO
|
||||
static void example_setup_sync_strategy(mcpwm_timer_handle_t timers[])
|
||||
{
|
||||
// +----GPIO----+
|
||||
// | | |
|
||||
// | | |
|
||||
// v v v
|
||||
// timer0 timer1 timer2
|
||||
ESP_LOGI(TAG, "Create GPIO sync source");
|
||||
mcpwm_sync_handle_t gpio_sync_source = NULL;
|
||||
mcpwm_gpio_sync_src_config_t gpio_sync_config = {
|
||||
.group_id = 0, // GPIO fault should be in the same group of the above timers
|
||||
.gpio_num = EXAMPLE_SYNC_GPIO,
|
||||
.flags.pull_down = true,
|
||||
.flags.active_neg = false, // by default, a posedge pulse can trigger a sync event
|
||||
.flags.io_loop_back = true, // then we can trigger a sync event using `gpio_set_level` on the same GPIO
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_source));
|
||||
|
||||
ESP_LOGI(TAG, "Set timers to sync on the GPIO");
|
||||
mcpwm_timer_sync_phase_config_t sync_phase_config = {
|
||||
.count_value = 0,
|
||||
.direction = MCPWM_TIMER_DIRECTION_UP,
|
||||
.sync_src = gpio_sync_source,
|
||||
};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[i], &sync_phase_config));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Trigger a pulse on the GPIO as a sync event");
|
||||
gpio_set_level(EXAMPLE_SYNC_GPIO, 0);
|
||||
gpio_set_level(EXAMPLE_SYNC_GPIO, 1);
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_SYNC_FROM_GPIO
|
||||
|
||||
#if CONFIG_EXAMPLE_SYNC_FROM_TEZ
|
||||
static void example_setup_sync_strategy(mcpwm_timer_handle_t timers[])
|
||||
{
|
||||
// +->timer1
|
||||
// (TEZ) |
|
||||
// timer0---+
|
||||
// |
|
||||
// +->timer2
|
||||
ESP_LOGI(TAG, "Create TEZ sync source from timer0");
|
||||
mcpwm_sync_handle_t timer_sync_source = NULL;
|
||||
mcpwm_timer_sync_src_config_t timer_sync_config = {
|
||||
.timer_event = MCPWM_TIMER_EVENT_EMPTY, // generate sync event on timer empty
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_new_timer_sync_src(timers[0], &timer_sync_config, &timer_sync_source));
|
||||
|
||||
ESP_LOGI(TAG, "Set other timers sync to the first timer");
|
||||
mcpwm_timer_sync_phase_config_t sync_phase_config = {
|
||||
.count_value = 0,
|
||||
.direction = MCPWM_TIMER_DIRECTION_UP,
|
||||
.sync_src = timer_sync_source,
|
||||
};
|
||||
for (int i = 1; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[i], &sync_phase_config));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Wait some time for the timer TEZ event");
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_SYNC_FROM_TEZ
|
||||
|
||||
#if CONFIG_EXAMPLE_SYNC_FROM_SOFT
|
||||
static void example_setup_sync_strategy(mcpwm_timer_handle_t timers[])
|
||||
{
|
||||
// soft
|
||||
// |
|
||||
// v
|
||||
// +-timer0--+
|
||||
// | |
|
||||
// v v
|
||||
// timer1 timer2
|
||||
ESP_LOGI(TAG, "Create software sync source");
|
||||
mcpwm_sync_handle_t soft_sync_source = NULL;
|
||||
mcpwm_soft_sync_config_t soft_sync_config = {};
|
||||
ESP_ERROR_CHECK(mcpwm_new_soft_sync_src(&soft_sync_config, &soft_sync_source));
|
||||
|
||||
ESP_LOGI(TAG, "Create timer sync source to propagate the sync event");
|
||||
mcpwm_sync_handle_t timer_sync_source;
|
||||
mcpwm_timer_sync_src_config_t timer_sync_config = {
|
||||
.flags.propagate_input_sync = true,
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_new_timer_sync_src(timers[0], &timer_sync_config, &timer_sync_source));
|
||||
|
||||
ESP_LOGI(TAG, "Set sync phase for timers");
|
||||
mcpwm_timer_sync_phase_config_t sync_phase_config = {
|
||||
.count_value = 0,
|
||||
.direction = MCPWM_TIMER_DIRECTION_UP,
|
||||
.sync_src = soft_sync_source,
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[0], &sync_phase_config));
|
||||
sync_phase_config.sync_src = timer_sync_source;
|
||||
for (int i = 1; i < 3; ++i) {
|
||||
ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[i], &sync_phase_config));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Trigger the software sync event");
|
||||
ESP_ERROR_CHECK(mcpwm_soft_sync_activate(soft_sync_source));
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_SYNC_FROM_SOFT
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Create timers");
|
||||
mcpwm_timer_handle_t timers[3];
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = EXAMPLE_TIMER_RESOLUTION_HZ,
|
||||
.period_ticks = EXAMPLE_TIMER_PERIOD,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Create operators");
|
||||
mcpwm_oper_handle_t operators[3];
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0, // operator should be in the same group of the above timers
|
||||
};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &operators[i]));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Connect timers and operators with each other");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(operators[i], timers[i]));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Create comparators");
|
||||
mcpwm_cmpr_handle_t comparators[3];
|
||||
mcpwm_comparator_config_t compare_config = {
|
||||
.flags.update_cmp_on_tez = true,
|
||||
};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_new_comparator(operators[i], &compare_config, &comparators[i]));
|
||||
// init compare for each comparator
|
||||
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[i], 200));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Create generators");
|
||||
mcpwm_gen_handle_t generators[3];
|
||||
const int gen_gpios[3] = {EXAMPLE_GEN_GPIO0, EXAMPLE_GEN_GPIO1, EXAMPLE_GEN_GPIO2};
|
||||
mcpwm_generator_config_t gen_config = {};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
gen_config.gen_gpio_num = gen_gpios[i];
|
||||
ESP_ERROR_CHECK(mcpwm_new_generator(operators[i], &gen_config, &generators[i]));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Set generator actions on timer and compare event");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(generators[i],
|
||||
// when the timer value is zero, and is counting up, set output to high
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(generators[i],
|
||||
// when compare event happens, and timer is counting up, set output to low
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparators[i], MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Start timers one by one, so they are not synced");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_timer_enable(timers[i]));
|
||||
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Manually added this "IDLE" phase, which can help us distinguish the wave forms before and after sync
|
||||
ESP_LOGI(TAG, "Force the output level to low, timer still running");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i], 0, true));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Setup sync strategy");
|
||||
example_setup_sync_strategy(timers);
|
||||
|
||||
ESP_LOGI(TAG, "Now the output PWMs should in sync");
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
// remove the force level on the generator, so that we can see the PWM again
|
||||
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i], -1, true));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
24
examples/peripherals/mcpwm/mcpwm_sync/pytest_mcpwm_sync.py
Normal file
24
examples/peripherals/mcpwm/mcpwm_sync/pytest_mcpwm_sync.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', [
|
||||
pytest.param('gpio', marks=[pytest.mark.esp32, pytest.mark.esp32s3]),
|
||||
pytest.param('tez', marks=[pytest.mark.esp32, pytest.mark.esp32s3]),
|
||||
pytest.param('soft', marks=[pytest.mark.esp32s3]),
|
||||
], indirect=True)
|
||||
def test_mcpwm_sync_example(dut: Dut) -> None:
|
||||
dut.expect_exact('example: Create timers')
|
||||
dut.expect_exact('example: Create operators')
|
||||
dut.expect_exact('example: Create comparators')
|
||||
dut.expect_exact('example: Create generators')
|
||||
dut.expect_exact('example: Set generator actions on timer and compare event')
|
||||
dut.expect_exact('example: Start timers one by one, so they are not synced')
|
||||
dut.expect_exact('example: Setup sync strategy')
|
||||
dut.expect_exact('example: Now the output PWMs should in sync')
|
1
examples/peripherals/mcpwm/mcpwm_sync/sdkconfig.ci.gpio
Normal file
1
examples/peripherals/mcpwm/mcpwm_sync/sdkconfig.ci.gpio
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_SYNC_FROM_GPIO=y
|
1
examples/peripherals/mcpwm/mcpwm_sync/sdkconfig.ci.soft
Normal file
1
examples/peripherals/mcpwm/mcpwm_sync/sdkconfig.ci.soft
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_SYNC_FROM_SOFT=y
|
1
examples/peripherals/mcpwm/mcpwm_sync/sdkconfig.ci.tez
Normal file
1
examples/peripherals/mcpwm/mcpwm_sync/sdkconfig.ci.tez
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_SYNC_FROM_TEZ=y
|
@@ -1,74 +0,0 @@
|
||||
| Supported Targets | ESP32 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- |
|
||||
|
||||
# MCPWM sync Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example aims to show howto sync those timers within the same MCPWM unit to produce fully synchronized output.
|
||||
|
||||
The example will:
|
||||
|
||||
- init MCPWM
|
||||
- sync all three timers with the help of one extra GPIO
|
||||
- mess the synchronized timers by stopping and restarting
|
||||
- sync all three timers with software sync event, no GPIO required. (Only targets with `SOC_MCPWM_SWSYNC_CAN_PROPAGATE` ability can support).
|
||||
- sync all three timers, but adding 10% delay between pulses from different channels
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* An ESP32/ESP32S3 development board
|
||||
|
||||
It is recommended to have an oscilloscope or logic analyzer to verify the output pulse
|
||||
|
||||
Connection :
|
||||
|
||||
| Pin | Func | Mode |
|
||||
| :---------: | :----------------: | :----: |
|
||||
| GPIO_NUM_16 | MCPWM0.Timer0.GenA | Output |
|
||||
| GPIO_NUM_17 | MCPWM0.Timer1.GenA | Output |
|
||||
| GPIO_NUM_18 | MCPWM0.Timer2.GenA | Output |
|
||||
| GPIO_NUM_21 | GPIO_SYNC0 | INPUT |
|
||||
| GPIO_NUM_19 | simulate input | OUTPUT |
|
||||
|
||||
GPIO_NUM_21 and GPIO_NUM_19 **SHOULD** be wired together to provide simulated input.
|
||||
|
||||
Above pin selection can be changed within file `mcpwm_sync_example.c`.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (306) sync_example: MCPWM sync example
|
||||
I (306) sync_example: PWM started, not synchronized
|
||||
I (3316) sync_example: Sync timers with GPIO approach
|
||||
I (3326) sync_example: Output should already be synchronized
|
||||
I (6326) sync_example: force synchronous lost
|
||||
I (9326) sync_example: Output should already be synchronized on esp32s3
|
||||
I (12336) sync_example: Each output pulse should be placed with 10 percents of period
|
||||
```
|
||||
|
||||
Overall pulse graph:
|
||||
|
||||

|
||||
|
||||
Sync:
|
||||
|
||||

|
||||
|
||||
Sync with phase:
|
||||
|
||||

|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "mcpwm_sync_example.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
const static char *TAG = "example";
|
||||
|
||||
#define TARGET_MCPWM_UNIT MCPWM_UNIT_0
|
||||
#define TIMER0_OUTPUT_GPIO GPIO_NUM_16
|
||||
#define TIMER1_OUTPUT_GPIO GPIO_NUM_17
|
||||
#define TIMER2_OUTPUT_GPIO GPIO_NUM_18
|
||||
#define SIMU_GPIO_SYNC_SOURCE_GPIO GPIO_NUM_21
|
||||
#define SIMU_GPIO_SYNC_SIMULATE_GPIO GPIO_NUM_19
|
||||
|
||||
void app_main(void) {
|
||||
ESP_LOGI(TAG, "MCPWM sync example");
|
||||
|
||||
// init MCPWM: 10% duty cycle on all three timers in MCPWM unit 0 (currently not synchronous)
|
||||
mcpwm_config_t pwm_config = {
|
||||
.frequency = 1000,
|
||||
.cmpr_a = 10,
|
||||
.cmpr_b = 0,
|
||||
.counter_mode = MCPWM_UP_COUNTER,
|
||||
.duty_mode = MCPWM_DUTY_MODE_0,
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_init(TARGET_MCPWM_UNIT, MCPWM_TIMER_0, &pwm_config));
|
||||
ESP_ERROR_CHECK(mcpwm_init(TARGET_MCPWM_UNIT, MCPWM_TIMER_1, &pwm_config));
|
||||
ESP_ERROR_CHECK(mcpwm_init(TARGET_MCPWM_UNIT, MCPWM_TIMER_2, &pwm_config));
|
||||
|
||||
// bind output to GPIO
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
|
||||
ESP_LOGI(TAG, "PWM started, not synchronized");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
// temporarily disable GPIO output, by binding to GenBs which have 0 output
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0B, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1B, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2B, TIMER2_OUTPUT_GPIO));
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
ESP_LOGI(TAG, "Sync timers with GPIO approach");
|
||||
// first configure sync source
|
||||
mcpwm_sync_config_t sync_conf = {
|
||||
.sync_sig = MCPWM_SELECT_GPIO_SYNC0,
|
||||
.timer_val = 0,
|
||||
.count_direction = MCPWM_TIMER_DIRECTION_UP,
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_sync_configure(TARGET_MCPWM_UNIT, MCPWM_TIMER_0, &sync_conf));
|
||||
ESP_ERROR_CHECK(mcpwm_sync_configure(TARGET_MCPWM_UNIT, MCPWM_TIMER_1, &sync_conf));
|
||||
ESP_ERROR_CHECK(mcpwm_sync_configure(TARGET_MCPWM_UNIT, MCPWM_TIMER_2, &sync_conf));
|
||||
// then configure GPIO
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM_SYNC_0, SIMU_GPIO_SYNC_SOURCE_GPIO));
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = BIT64(SIMU_GPIO_SYNC_SIMULATE_GPIO);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 0));
|
||||
ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 1));
|
||||
// wait for at least one TEP
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// re-enable GPIO output, to see the result
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
|
||||
ESP_LOGI(TAG, "Output should already be synchronized");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// stop and restart timers to mess them
|
||||
ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_2));
|
||||
ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_1));
|
||||
ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_0));
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
ESP_ERROR_CHECK(mcpwm_start(TARGET_MCPWM_UNIT, MCPWM_TIMER_0));
|
||||
ESP_ERROR_CHECK(mcpwm_start(TARGET_MCPWM_UNIT, MCPWM_TIMER_1));
|
||||
ESP_ERROR_CHECK(mcpwm_start(TARGET_MCPWM_UNIT, MCPWM_TIMER_2));
|
||||
ESP_LOGI(TAG, "force synchronous lost");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
// temporarily disable GPIO output, by binding to GenBs which have 0 output
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0B, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1B, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2B, TIMER2_OUTPUT_GPIO));
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
#ifdef SOC_MCPWM_SWSYNC_CAN_PROPAGATE
|
||||
// use the trick that only available on esp32s3
|
||||
mcpwm_set_timer_sync_output(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_SWSYNC_SOURCE_SYNCIN);
|
||||
sync_conf.sync_sig = MCPWM_SELECT_TIMER0_SYNC;
|
||||
mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_0, &sync_conf);
|
||||
mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_1, &sync_conf);
|
||||
mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_2, &sync_conf);
|
||||
// then send soft sync event to timer0
|
||||
mcpwm_timer_trigger_soft_sync(MCPWM_UNIT_0, MCPWM_TIMER_0);
|
||||
// re-enable GPIO output
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
|
||||
ESP_LOGI(TAG, "Output should already be synchronized on esp32s3");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
#endif
|
||||
|
||||
// temporarily disable GPIO output, by binding to GenBs which have 0 output
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0B, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1B, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2B, TIMER2_OUTPUT_GPIO));
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
// create phase between each timer.
|
||||
// for this case all timers has 10% of period phase between each other
|
||||
sync_conf.sync_sig = MCPWM_SELECT_GPIO_SYNC0;
|
||||
sync_conf.timer_val = 0; // no phase applied
|
||||
mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_0, &sync_conf);
|
||||
sync_conf.timer_val = 900; // fill the counter with 90.0% of period will cause next pulse being delayed 10% period
|
||||
mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_1, &sync_conf);
|
||||
sync_conf.timer_val = 800; // fill the counter with 80.0% of period will cause next pulse being delayed 20% period
|
||||
mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_2, &sync_conf);
|
||||
// trigger positive edge
|
||||
ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 0));
|
||||
ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 1));
|
||||
// wait for at least one TEP
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// re-enable GPIO output, to see the result
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
|
||||
ESP_LOGI(TAG, "Each output pulse should be placed with 10 percents of period");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_2));
|
||||
ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_1));
|
||||
ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_0));
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 35 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Reference in New Issue
Block a user