example: update MCPWM sync example with new driver API

This commit is contained in:
morris
2022-05-28 17:06:06 +08:00
parent 1557a533fe
commit 169a43b8eb
15 changed files with 349 additions and 223 deletions

View File

@@ -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)

View 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.

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "mcpwm_sync_example_main.c"
INCLUDE_DIRS ".")

View 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

View File

@@ -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));
}

View 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')

View File

@@ -0,0 +1 @@
CONFIG_EXAMPLE_SYNC_FROM_GPIO=y

View File

@@ -0,0 +1 @@
CONFIG_EXAMPLE_SYNC_FROM_SOFT=y

View File

@@ -0,0 +1 @@
CONFIG_EXAMPLE_SYNC_FROM_TEZ=y

View File

@@ -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:
![](readme_res/overall.png)
Sync:
![](readme_res/synced.png)
Sync with phase:
![](readme_res/sync_phase.png)
## 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.

View File

@@ -1,2 +0,0 @@
idf_component_register(SRCS "mcpwm_sync_example.c"
INCLUDE_DIRS ".")

View File

@@ -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