| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2024-01-31 16:07:51 +08:00
										 |  |  |  * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <sys/cdefs.h>
 | 
					
						
							|  |  |  | #include "sdkconfig.h"
 | 
					
						
							|  |  |  | #if CONFIG_MCPWM_ENABLE_DEBUG_LOG
 | 
					
						
							|  |  |  | // The local log level must be defined before including esp_log.h
 | 
					
						
							|  |  |  | // Set the maximum log level for this source file
 | 
					
						
							|  |  |  | #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include "freertos/FreeRTOS.h"
 | 
					
						
							|  |  |  | #include "esp_attr.h"
 | 
					
						
							|  |  |  | #include "esp_check.h"
 | 
					
						
							|  |  |  | #include "esp_err.h"
 | 
					
						
							|  |  |  | #include "esp_log.h"
 | 
					
						
							|  |  |  | #include "soc/soc_caps.h"
 | 
					
						
							|  |  |  | #include "soc/mcpwm_periph.h"
 | 
					
						
							|  |  |  | #include "hal/mcpwm_ll.h"
 | 
					
						
							|  |  |  | #include "driver/gpio.h"
 | 
					
						
							|  |  |  | #include "driver/mcpwm_gen.h"
 | 
					
						
							|  |  |  | #include "mcpwm_private.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *TAG = "mcpwm"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static esp_err_t mcpwm_generator_register_to_operator(mcpwm_gen_t *gen, mcpwm_oper_t *oper) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int gen_id = -1; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     for (int i = 0; i < SOC_MCPWM_GENERATORS_PER_OPERATOR; i++) { | 
					
						
							|  |  |  |         if (!oper->generators[i]) { | 
					
						
							|  |  |  |             oper->generators[i] = gen; | 
					
						
							|  |  |  |             gen_id = i; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free generator in operator (%d,%d)", oper->group->group_id, oper->oper_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gen->gen_id = gen_id; | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     gen->oper = oper; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void mcpwm_generator_unregister_from_operator(mcpwm_gen_t *gen) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     int gen_id = gen->gen_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     portENTER_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     oper->generators[gen_id] = NULL; | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 16:33:42 +08:00
										 |  |  | static esp_err_t mcpwm_generator_destroy(mcpwm_gen_t *gen) | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     if (gen->oper) { | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |         mcpwm_generator_unregister_from_operator(gen); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     free(gen); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t mcpwm_new_generator(mcpwm_oper_handle_t oper, const mcpwm_generator_config_t *config, mcpwm_gen_handle_t *ret_gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_err_t ret = ESP_OK; | 
					
						
							|  |  |  |     mcpwm_gen_t *gen = NULL; | 
					
						
							|  |  |  |     ESP_GOTO_ON_FALSE(oper && config && ret_gen, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gen = heap_caps_calloc(1, sizeof(mcpwm_gen_t), MCPWM_MEM_ALLOC_CAPS); | 
					
						
							|  |  |  |     ESP_GOTO_ON_FALSE(gen, ESP_ERR_NO_MEM, err, TAG, "no mem for generator"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ESP_GOTO_ON_ERROR(mcpwm_generator_register_to_operator(gen, oper), err, TAG, "register generator failed"); | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     mcpwm_hal_context_t *hal = &group->hal; | 
					
						
							|  |  |  |     int oper_id = oper->oper_id; | 
					
						
							|  |  |  |     int gen_id = gen->gen_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // reset generator
 | 
					
						
							|  |  |  |     mcpwm_hal_generator_reset(hal, oper_id, gen_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // GPIO configuration
 | 
					
						
							|  |  |  |     gpio_config_t gpio_conf = { | 
					
						
							|  |  |  |         .intr_type = GPIO_INTR_DISABLE, | 
					
						
							| 
									
										
										
										
											2023-07-19 11:27:11 +08:00
										 |  |  |         // also enable the input path if `io_loop_back` is enabled
 | 
					
						
							|  |  |  |         .mode = (config->flags.io_od_mode ? GPIO_MODE_OUTPUT_OD : GPIO_MODE_OUTPUT) | (config->flags.io_loop_back ? GPIO_MODE_INPUT : 0), | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |         .pin_bit_mask = (1ULL << config->gen_gpio_num), | 
					
						
							| 
									
										
										
										
											2023-07-14 21:44:03 +02:00
										 |  |  |         .pull_down_en = config->flags.pull_down, | 
					
						
							|  |  |  |         .pull_up_en = config->flags.pull_up, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     }; | 
					
						
							|  |  |  |     ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config gen GPIO failed"); | 
					
						
							|  |  |  |     esp_rom_gpio_connect_out_signal(config->gen_gpio_num, | 
					
						
							|  |  |  |                                     mcpwm_periph_signals.groups[group->group_id].operators[oper_id].generators[gen_id].pwm_sig, | 
					
						
							|  |  |  |                                     config->flags.invert_pwm, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // fill in other generator members
 | 
					
						
							|  |  |  |     gen->gen_gpio_num = config->gen_gpio_num; | 
					
						
							|  |  |  |     gen->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; | 
					
						
							|  |  |  |     *ret_gen = gen; | 
					
						
							|  |  |  |     ESP_LOGD(TAG, "new generator (%d,%d,%d) at %p, GPIO %d", group->group_id, oper_id, gen_id, gen, gen->gen_gpio_num); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  |     if (gen) { | 
					
						
							| 
									
										
										
										
											2023-02-16 16:33:42 +08:00
										 |  |  |         mcpwm_generator_destroy(gen); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t mcpwm_del_generator(mcpwm_gen_handle_t gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ESP_LOGD(TAG, "del generator (%d,%d,%d)", group->group_id, oper->oper_id, gen->gen_id); | 
					
						
							| 
									
										
										
										
											2024-01-31 16:07:51 +08:00
										 |  |  |     // reset GPIO
 | 
					
						
							|  |  |  |     gpio_reset_pin(gen->gen_gpio_num); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     // recycle memory resource
 | 
					
						
							| 
									
										
										
										
											2023-02-16 16:33:42 +08:00
										 |  |  |     ESP_RETURN_ON_ERROR(mcpwm_generator_destroy(gen), TAG, "destroy generator failed"); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t mcpwm_generator_set_force_level(mcpwm_gen_handle_t gen, int level, bool hold_on) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen && level <= 1, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     mcpwm_hal_context_t *hal = &group->hal; | 
					
						
							|  |  |  |     int oper_id = oper->oper_id; | 
					
						
							|  |  |  |     int gen_id = gen->gen_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (level < 0) { // to remove the force level
 | 
					
						
							|  |  |  |         if (hold_on) { | 
					
						
							|  |  |  |             mcpwm_ll_gen_disable_continue_force_action(hal->dev, oper_id, gen_id); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             mcpwm_ll_gen_disable_noncontinue_force_action(hal->dev, oper_id, gen_id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { // to enable the force output level
 | 
					
						
							|  |  |  |         if (hold_on) { | 
					
						
							|  |  |  |             mcpwm_ll_gen_set_continue_force_level(hal->dev, oper_id, gen_id, level); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             mcpwm_ll_gen_set_noncontinue_force_level(hal->dev, oper_id, gen_id, level); | 
					
						
							|  |  |  |             mcpwm_ll_gen_trigger_noncontinue_force_action(hal->dev, oper_id, gen_id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-03 13:28:43 +08:00
										 |  |  | esp_err_t mcpwm_generator_set_action_on_timer_event(mcpwm_gen_handle_t gen, mcpwm_gen_timer_event_action_t ev_act) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(ev_act.event != MCPWM_TIMER_EVENT_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid event"); | 
					
						
							|  |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     mcpwm_timer_t *timer = oper->timer; | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_STATE, TAG, "no timer is connected to the operator"); | 
					
						
							|  |  |  |     bool invalid_utep = (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) && | 
					
						
							|  |  |  |                         (ev_act.direction == MCPWM_TIMER_DIRECTION_UP) && | 
					
						
							|  |  |  |                         (ev_act.event == MCPWM_TIMER_EVENT_FULL); | 
					
						
							|  |  |  |     bool invalid_dtez = (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) && | 
					
						
							|  |  |  |                         (ev_act.direction == MCPWM_TIMER_DIRECTION_DOWN) && | 
					
						
							|  |  |  |                         (ev_act.event == MCPWM_TIMER_EVENT_EMPTY); | 
					
						
							|  |  |  |     if (invalid_utep || invalid_dtez) { | 
					
						
							|  |  |  |         ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "UTEP and DTEZ can't be reached under MCPWM_TIMER_COUNT_MODE_UP_DOWN mode"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     mcpwm_ll_generator_set_action_on_timer_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							|  |  |  |             ev_act.direction, ev_act.event, ev_act.action); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | esp_err_t mcpwm_generator_set_actions_on_timer_event(mcpwm_gen_handle_t gen, mcpwm_gen_timer_event_action_t ev_act, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     mcpwm_timer_t *timer = oper->timer; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_STATE, TAG, "no timer is connected to the operator"); | 
					
						
							|  |  |  |     mcpwm_gen_timer_event_action_t ev_act_itor = ev_act; | 
					
						
							|  |  |  |     bool invalid_utep = false; | 
					
						
							|  |  |  |     bool invalid_dtez = false; | 
					
						
							|  |  |  |     va_list it; | 
					
						
							|  |  |  |     va_start(it, ev_act); | 
					
						
							|  |  |  |     while (ev_act_itor.event != MCPWM_TIMER_EVENT_INVALID) { | 
					
						
							|  |  |  |         invalid_utep = (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) && | 
					
						
							|  |  |  |                        (ev_act_itor.direction == MCPWM_TIMER_DIRECTION_UP) && | 
					
						
							|  |  |  |                        (ev_act_itor.event == MCPWM_TIMER_EVENT_FULL); | 
					
						
							|  |  |  |         invalid_dtez = (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) && | 
					
						
							|  |  |  |                        (ev_act_itor.direction == MCPWM_TIMER_DIRECTION_DOWN) && | 
					
						
							|  |  |  |                        (ev_act_itor.event == MCPWM_TIMER_EVENT_EMPTY); | 
					
						
							|  |  |  |         if (invalid_utep || invalid_dtez) { | 
					
						
							|  |  |  |             va_end(it); | 
					
						
							|  |  |  |             ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "UTEP and DTEZ can't be reached under MCPWM_TIMER_COUNT_MODE_UP_DOWN mode"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |         mcpwm_ll_generator_set_action_on_timer_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |                 ev_act_itor.direction, ev_act_itor.event, ev_act_itor.action); | 
					
						
							|  |  |  |         ev_act_itor = va_arg(it, mcpwm_gen_timer_event_action_t); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     va_end(it); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-03 13:28:43 +08:00
										 |  |  | esp_err_t mcpwm_generator_set_action_on_compare_event(mcpwm_gen_handle_t gen, mcpwm_gen_compare_event_action_t ev_act) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(ev_act.comparator, ESP_ERR_INVALID_ARG, TAG, "invalid comparator"); | 
					
						
							|  |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     mcpwm_ll_generator_set_action_on_compare_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							|  |  |  |             ev_act.direction, ev_act.comparator->cmpr_id, ev_act.action); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | esp_err_t mcpwm_generator_set_actions_on_compare_event(mcpwm_gen_handle_t gen, mcpwm_gen_compare_event_action_t ev_act, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     mcpwm_gen_compare_event_action_t ev_act_itor = ev_act; | 
					
						
							|  |  |  |     va_list it; | 
					
						
							|  |  |  |     va_start(it, ev_act); | 
					
						
							|  |  |  |     while (ev_act_itor.comparator) { | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |         mcpwm_ll_generator_set_action_on_compare_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |                 ev_act_itor.direction, ev_act_itor.comparator->cmpr_id, ev_act_itor.action); | 
					
						
							|  |  |  |         ev_act_itor = va_arg(it, mcpwm_gen_compare_event_action_t); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     va_end(it); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-03 13:28:43 +08:00
										 |  |  | esp_err_t mcpwm_generator_set_action_on_brake_event(mcpwm_gen_handle_t gen, mcpwm_gen_brake_event_action_t ev_act) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(ev_act.brake_mode != MCPWM_OPER_BRAKE_MODE_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid brake mode"); | 
					
						
							|  |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     mcpwm_ll_generator_set_action_on_brake_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							|  |  |  |             ev_act.direction, ev_act.brake_mode, ev_act.action); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | esp_err_t mcpwm_generator_set_actions_on_brake_event(mcpwm_gen_handle_t gen, mcpwm_gen_brake_event_action_t ev_act, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     mcpwm_gen_brake_event_action_t ev_act_itor = ev_act; | 
					
						
							|  |  |  |     va_list it; | 
					
						
							|  |  |  |     va_start(it, ev_act); | 
					
						
							|  |  |  |     while (ev_act_itor.brake_mode != MCPWM_OPER_BRAKE_MODE_INVALID) { | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |         mcpwm_ll_generator_set_action_on_brake_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |                 ev_act_itor.direction, ev_act_itor.brake_mode, ev_act_itor.action); | 
					
						
							|  |  |  |         ev_act_itor = va_arg(it, mcpwm_gen_brake_event_action_t); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     va_end(it); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							| 
									
										
										
										
											2023-07-17 11:40:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t mcpwm_generator_set_action_on_fault_event(mcpwm_gen_handle_t gen, mcpwm_gen_fault_event_action_t ev_act) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							|  |  |  |     mcpwm_fault_t *fault = ev_act.fault; | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(fault->type == MCPWM_FAULT_TYPE_GPIO, ESP_ERR_NOT_SUPPORTED, TAG, "not supported fault type"); | 
					
						
							|  |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     // check the remained triggers
 | 
					
						
							|  |  |  |     int trigger_id = -1; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     for (int i = 0; i < SOC_MCPWM_TRIGGERS_PER_OPERATOR; i++) { | 
					
						
							|  |  |  |         if (oper->triggers[i] == MCPWM_TRIGGER_NO_ASSIGN) { | 
					
						
							|  |  |  |             trigger_id = i; | 
					
						
							|  |  |  |             oper->triggers[i] = MCPWM_TRIGGER_GPIO_FAULT; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(trigger_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free trigger in operator (%d,%d)", group->group_id, oper->oper_id); | 
					
						
							|  |  |  |     mcpwm_gpio_fault_t *gpio_fault = __containerof(fault, mcpwm_gpio_fault_t, base); | 
					
						
							|  |  |  |     mcpwm_ll_operator_set_trigger_from_gpio_fault(group->hal.dev, oper->oper_id, trigger_id, gpio_fault->fault_id); | 
					
						
							|  |  |  |     mcpwm_ll_generator_set_action_on_trigger_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							|  |  |  |             ev_act.direction, trigger_id, ev_act.action); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t mcpwm_generator_set_action_on_sync_event(mcpwm_gen_handle_t gen, mcpwm_gen_sync_event_action_t ev_act) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(gen, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							|  |  |  |     mcpwm_oper_t *oper = gen->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							|  |  |  |     // check the remained triggers
 | 
					
						
							|  |  |  |     int trigger_id = -1; | 
					
						
							|  |  |  |     int trigger_sync_used = 0; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     for (int i = 0; i < SOC_MCPWM_TRIGGERS_PER_OPERATOR; i++) { | 
					
						
							|  |  |  |         if (oper->triggers[i] == MCPWM_TRIGGER_SYNC_EVENT) { | 
					
						
							|  |  |  |             trigger_sync_used = 1; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } else if (oper->triggers[i] == MCPWM_TRIGGER_NO_ASSIGN) { | 
					
						
							|  |  |  |             trigger_id = i; | 
					
						
							|  |  |  |             oper->triggers[i] = MCPWM_TRIGGER_SYNC_EVENT; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(!trigger_sync_used, ESP_ERR_INVALID_STATE, TAG, "only one sync supported"); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(trigger_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free trigger in operator (%d,%d)", group->group_id, oper->oper_id); | 
					
						
							|  |  |  |     mcpwm_ll_operator_set_trigger_from_sync(group->hal.dev, oper->oper_id, trigger_id); | 
					
						
							|  |  |  |     mcpwm_ll_generator_set_action_on_trigger_event(group->hal.dev, oper->oper_id, gen->gen_id, | 
					
						
							|  |  |  |             ev_act.direction, trigger_id, ev_act.action); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t mcpwm_generator_set_dead_time(mcpwm_gen_handle_t in_generator, mcpwm_gen_handle_t out_generator, const mcpwm_dead_time_config_t *config) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(in_generator && out_generator && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     ESP_RETURN_ON_FALSE(in_generator->oper == out_generator->oper, ESP_ERR_INVALID_ARG, TAG, "in/out generator are not derived from the same operator"); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     ESP_RETURN_ON_FALSE(config->negedge_delay_ticks < MCPWM_LL_MAX_DEAD_DELAY && config->posedge_delay_ticks < MCPWM_LL_MAX_DEAD_DELAY, | 
					
						
							|  |  |  |                         ESP_ERR_INVALID_ARG, TAG, "delay time out of range"); | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     mcpwm_oper_t *oper = in_generator->oper; | 
					
						
							|  |  |  |     mcpwm_group_t *group = oper->group; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     mcpwm_hal_context_t *hal = &group->hal; | 
					
						
							| 
									
										
										
										
											2022-08-16 17:57:02 +08:00
										 |  |  |     int oper_id = oper->oper_id; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 16:29:20 +08:00
										 |  |  |     // one delay module can only be used by one generator at a time
 | 
					
						
							|  |  |  |     bool delay_module_conflict = false; | 
					
						
							|  |  |  |     portENTER_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     if (config->posedge_delay_ticks) { | 
					
						
							|  |  |  |         if (oper->posedge_delay_owner && oper->posedge_delay_owner != in_generator) { | 
					
						
							|  |  |  |             delay_module_conflict = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (config->negedge_delay_ticks) { | 
					
						
							|  |  |  |         if (oper->negedge_delay_owner && oper->negedge_delay_owner != in_generator) { | 
					
						
							|  |  |  |             delay_module_conflict = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!delay_module_conflict) { | 
					
						
							|  |  |  |         if (config->posedge_delay_ticks) { | 
					
						
							|  |  |  |             // set owner if delay module is used
 | 
					
						
							|  |  |  |             oper->posedge_delay_owner = in_generator; | 
					
						
							|  |  |  |         } else if (oper->posedge_delay_owner == in_generator) { | 
					
						
							|  |  |  |             // clear owner if delay module is previously used by in_generator, but now it is not used
 | 
					
						
							|  |  |  |             oper->posedge_delay_owner = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (config->negedge_delay_ticks) { | 
					
						
							|  |  |  |             oper->negedge_delay_owner = in_generator; | 
					
						
							|  |  |  |         } else if (oper->negedge_delay_owner == in_generator) { | 
					
						
							|  |  |  |             oper->negedge_delay_owner = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&oper->spinlock); | 
					
						
							|  |  |  |     ESP_RETURN_ON_FALSE(!delay_module_conflict, ESP_ERR_INVALID_STATE, TAG, "delay module is in use by other generator"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     // Note: to better understand the following code, you should read the deadtime module topology diagram in the TRM
 | 
					
						
							|  |  |  |     // check if we want to bypass the deadtime module
 | 
					
						
							|  |  |  |     bool bypass = (config->negedge_delay_ticks == 0) && (config->posedge_delay_ticks == 0); | 
					
						
							|  |  |  |     // check is we want to delay on the both edge
 | 
					
						
							|  |  |  |     bool delay_on_both_edge = config->posedge_delay_ticks && config->negedge_delay_ticks; | 
					
						
							|  |  |  |     int out_path_id = -1; | 
					
						
							|  |  |  |     if (bypass) { | 
					
						
							|  |  |  |         // out path is same to the input path of generator
 | 
					
						
							|  |  |  |         out_path_id = in_generator->gen_id; | 
					
						
							|  |  |  |     } else if (config->negedge_delay_ticks) { | 
					
						
							|  |  |  |         out_path_id = 1; // FED path
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         out_path_id = 0; // RED path
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     bool swap_path = out_path_id != out_generator->gen_id; | 
					
						
							|  |  |  |     mcpwm_ll_deadtime_bypass_path(hal->dev, oper_id, out_path_id, bypass); // S0/1
 | 
					
						
							|  |  |  |     if (!bypass) { | 
					
						
							|  |  |  |         if (config->posedge_delay_ticks) { | 
					
						
							|  |  |  |             mcpwm_ll_deadtime_red_select_generator(hal->dev, oper_id, in_generator->gen_id); // S4
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             mcpwm_ll_deadtime_fed_select_generator(hal->dev, oper_id, in_generator->gen_id); // S5
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         mcpwm_ll_deadtime_enable_deb(hal->dev, oper_id, delay_on_both_edge); // S8
 | 
					
						
							|  |  |  |         mcpwm_ll_deadtime_invert_outpath(hal->dev, oper_id, out_path_id, config->flags.invert_output); // S2/3
 | 
					
						
							|  |  |  |         mcpwm_ll_deadtime_swap_out_path(hal->dev, oper_id, out_generator->gen_id, swap_path); // S6/S7
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // set delay time
 | 
					
						
							|  |  |  |     if (config->posedge_delay_ticks) { | 
					
						
							|  |  |  |         mcpwm_ll_deadtime_set_rising_delay(hal->dev, oper_id, config->posedge_delay_ticks); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (config->negedge_delay_ticks) { | 
					
						
							|  |  |  |         mcpwm_ll_deadtime_set_falling_delay(hal->dev, oper_id, config->negedge_delay_ticks); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 13:08:48 +08:00
										 |  |  |     ESP_LOGD(TAG, "operator (%d,%d) dead time (R:%"PRIu32",F:%"PRIu32"), topology code:%"PRIx32, group->group_id, oper_id, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |              config->posedge_delay_ticks, config->negedge_delay_ticks, mcpwm_ll_deadtime_get_switch_topology(hal->dev, oper_id)); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } |