1 /* MCPWM sync example
2
3 This example code is in the Public Domain (or CC0 licensed, at your option.)
4
5 Unless required by applicable law or agreed to in writing, this
6 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND, either express or implied.
8 */
9
10 /*
11 * This example will show you how to use capture function to read HC-SR04 sonar sensor.
12 */
13
14 #include "freertos/FreeRTOS.h"
15 #include "freertos/task.h"
16 #include "freertos/queue.h"
17 #include "esp_rom_gpio.h"
18 #include "soc/mcpwm_periph.h"
19 #include "hal/gpio_hal.h"
20 #include "esp_log.h"
21 #include "esp_check.h"
22 #include "soc/rtc.h"
23 #include "driver/mcpwm.h"
24
25 const static char *TAG = "sync_example";
26
27 #define TARGET_MCPWM_UNIT MCPWM_UNIT_0
28 #define TIMER0_OUTPUT_GPIO GPIO_NUM_16
29 #define TIMER1_OUTPUT_GPIO GPIO_NUM_17
30 #define TIMER2_OUTPUT_GPIO GPIO_NUM_18
31 #define SIMU_GPIO_SYNC_SOURCE_GPIO GPIO_NUM_21
32 #define SIMU_GPIO_SYNC_SIMULATE_GPIO GPIO_NUM_19
33
app_main(void)34 void app_main(void) {
35 ESP_LOGI(TAG, "MCPWM sync example");
36
37 // init MCPWM: 10% duty cycle on all three timers in MCPWM unit 0 (currently not synchronous)
38 mcpwm_config_t pwm_config = {
39 .frequency = 1000,
40 .cmpr_a = 10,
41 .cmpr_b = 0,
42 .counter_mode = MCPWM_UP_COUNTER,
43 .duty_mode = MCPWM_DUTY_MODE_0,
44 };
45 ESP_ERROR_CHECK(mcpwm_init(TARGET_MCPWM_UNIT, MCPWM_TIMER_0, &pwm_config));
46 ESP_ERROR_CHECK(mcpwm_init(TARGET_MCPWM_UNIT, MCPWM_TIMER_1, &pwm_config));
47 ESP_ERROR_CHECK(mcpwm_init(TARGET_MCPWM_UNIT, MCPWM_TIMER_2, &pwm_config));
48
49 // bind output to GPIO
50 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
51 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
52 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
53 ESP_LOGI(TAG, "PWM started, not synchronized");
54
55 vTaskDelay(pdMS_TO_TICKS(1000));
56 // temporarily disable GPIO output, by binding to GenBs which have 0 output
57 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0B, TIMER0_OUTPUT_GPIO));
58 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1B, TIMER1_OUTPUT_GPIO));
59 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2B, TIMER2_OUTPUT_GPIO));
60 vTaskDelay(pdMS_TO_TICKS(2000));
61
62 ESP_LOGI(TAG, "Sync timers with GPIO approach");
63 // first configure sync source
64 mcpwm_sync_config_t sync_conf = {
65 .sync_sig = MCPWM_SELECT_GPIO_SYNC0,
66 .timer_val = 0,
67 .count_direction = MCPWM_TIMER_DIRECTION_UP,
68 };
69 ESP_ERROR_CHECK(mcpwm_sync_configure(TARGET_MCPWM_UNIT, MCPWM_TIMER_0, &sync_conf));
70 ESP_ERROR_CHECK(mcpwm_sync_configure(TARGET_MCPWM_UNIT, MCPWM_TIMER_1, &sync_conf));
71 ESP_ERROR_CHECK(mcpwm_sync_configure(TARGET_MCPWM_UNIT, MCPWM_TIMER_2, &sync_conf));
72 // then configure GPIO
73 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM_SYNC_0, SIMU_GPIO_SYNC_SOURCE_GPIO));
74 gpio_config_t io_conf = {};
75 io_conf.intr_type = GPIO_INTR_DISABLE;
76 io_conf.mode = GPIO_MODE_OUTPUT;
77 io_conf.pin_bit_mask = BIT64(SIMU_GPIO_SYNC_SIMULATE_GPIO);
78 io_conf.pull_down_en = 0;
79 io_conf.pull_up_en = 0;
80 ESP_ERROR_CHECK(gpio_config(&io_conf));
81 ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 0));
82 ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 1));
83 // wait for at least one TEP
84 vTaskDelay(pdMS_TO_TICKS(10));
85 // re-enable GPIO output, to see the result
86 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
87 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
88 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
89 ESP_LOGI(TAG, "Output should already be synchronized");
90
91 vTaskDelay(pdMS_TO_TICKS(1000));
92
93 // stop and restart timers to mess them
94 ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_2));
95 ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_1));
96 ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_0));
97 vTaskDelay(pdMS_TO_TICKS(2000));
98 ESP_ERROR_CHECK(mcpwm_start(TARGET_MCPWM_UNIT, MCPWM_TIMER_0));
99 ESP_ERROR_CHECK(mcpwm_start(TARGET_MCPWM_UNIT, MCPWM_TIMER_1));
100 ESP_ERROR_CHECK(mcpwm_start(TARGET_MCPWM_UNIT, MCPWM_TIMER_2));
101 ESP_LOGI(TAG, "force synchronous lost");
102
103 vTaskDelay(pdMS_TO_TICKS(1000));
104 // temporarily disable GPIO output, by binding to GenBs which have 0 output
105 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0B, TIMER0_OUTPUT_GPIO));
106 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1B, TIMER1_OUTPUT_GPIO));
107 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2B, TIMER2_OUTPUT_GPIO));
108 vTaskDelay(pdMS_TO_TICKS(2000));
109
110 #ifdef SOC_MCPWM_SWSYNC_CAN_PROPAGATE
111 // use the trick that only available on esp32s3
112 mcpwm_set_timer_sync_output(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_SWSYNC_SOURCE_SYNCIN);
113 sync_conf.sync_sig = MCPWM_SELECT_TIMER0_SYNC;
114 mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_0, &sync_conf);
115 mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_1, &sync_conf);
116 mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_2, &sync_conf);
117 // then send soft sync event to timer0
118 mcpwm_timer_trigger_soft_sync(MCPWM_UNIT_0, MCPWM_TIMER_0);
119 // re-enable GPIO output
120 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
121 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
122 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
123 ESP_LOGI(TAG, "Output should already be synchronized on esp32s3");
124
125 vTaskDelay(pdMS_TO_TICKS(1000));
126 #endif
127
128 // temporarily disable GPIO output, by binding to GenBs which have 0 output
129 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0B, TIMER0_OUTPUT_GPIO));
130 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1B, TIMER1_OUTPUT_GPIO));
131 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2B, TIMER2_OUTPUT_GPIO));
132 vTaskDelay(pdMS_TO_TICKS(2000));
133 // create phase between each timer.
134 // for this case all timers has 10% of period phase between each other
135 sync_conf.sync_sig = MCPWM_SELECT_GPIO_SYNC0;
136 sync_conf.timer_val = 0; // no phase applied
137 mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_0, &sync_conf);
138 sync_conf.timer_val = 900; // fill the counter with 90.0% of period will cause next pulse being delayed 10% period
139 mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_1, &sync_conf);
140 sync_conf.timer_val = 800; // fill the counter with 80.0% of period will cause next pulse being delayed 20% period
141 mcpwm_sync_configure(MCPWM_UNIT_0, MCPWM_TIMER_2, &sync_conf);
142 // trigger positive edge
143 ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 0));
144 ESP_ERROR_CHECK(gpio_set_level(SIMU_GPIO_SYNC_SIMULATE_GPIO, 1));
145 // wait for at least one TEP
146 vTaskDelay(pdMS_TO_TICKS(10));
147 // re-enable GPIO output, to see the result
148 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM0A, TIMER0_OUTPUT_GPIO));
149 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM1A, TIMER1_OUTPUT_GPIO));
150 ESP_ERROR_CHECK(mcpwm_gpio_init(TARGET_MCPWM_UNIT, MCPWM2A, TIMER2_OUTPUT_GPIO));
151 ESP_LOGI(TAG, "Each output pulse should be placed with 10 percents of period");
152
153 vTaskDelay(pdMS_TO_TICKS(1000));
154
155 ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_2));
156 ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_1));
157 ESP_ERROR_CHECK(mcpwm_stop(TARGET_MCPWM_UNIT, MCPWM_TIMER_0));
158 }
159