From f53dbc7f7abaa6054e843181d24ac381b3dfe5c3 Mon Sep 17 00:00:00 2001 From: Shang Zhou Date: Thu, 4 May 2023 15:45:15 +0800 Subject: [PATCH] docs: translate api-reference/peripherals.mcpwm.rst and library-and-framework index from scratch --- docs/en/api-reference/peripherals/mcpwm.rst | 411 ++++---- docs/en/libraries-and-frameworks/index.rst | 4 +- .../zh_CN/api-reference/peripherals/mcpwm.rst | 948 +++++++++++++++++- docs/zh_CN/libraries-and-frameworks/index.rst | 10 +- 4 files changed, 1191 insertions(+), 182 deletions(-) diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index 131e95da2d..d42738d9d3 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -1,12 +1,15 @@ Motor Control Pulse Width Modulator (MCPWM) =========================================== -The MCPWM peripheral is a versatile PWM generator, which contains various submodules to make it a key element in power electronic applications like motor control, digital power and so on. Typically, the MCPWM peripheral can be used in the following scenarios: +:link_to_translation:`zh_CN:[中文]` + + +The MCPWM peripheral is a versatile PWM generator, which contains various submodules to make it a key element in power electronic applications like motor control, digital power, and so on. Typically, the MCPWM peripheral can be used in the following scenarios: - Digital motor control, e.g. brushed/brushless DC motor, RC servo motor -- Switch mode based digital power conversion +- Switch mode-based digital power conversion - Power DAC, where the duty cycle is equivalent to a DAC analog value -- Calculate external pulse width, and convert it into other analog value like speed, distance +- Calculate external pulse width, and convert it into other analog values like speed, distance - Generate Space Vector PWM (SVPWM) signals for Field Oriented Control (FOC) The main submodules are listed in the following diagram: @@ -15,38 +18,41 @@ The main submodules are listed in the following diagram: :caption: MCPWM Overview :align: center -- **MCPWM Timer**: The time base of the final PWM signal, it also determines the event timing of other submodules. -- **MCPWM Operator**: The key module that is responsible for generating the PWM waveforms. It consists of other submodules, like comparator, PWM generator, dead-time and carrier modulator. -- **MCPWM Comparator**: The compare module takes the time-base count value as input, and continuously compare to the threshold value that configured by user. When the time-base counter is equal to any of the threshold value, an compare event will be generated and the MCPWM generator can update its level accordingly. -- **MCPWM Generator**: One MCPWM generator can generate a pair of PWM waves, complementarily or independently, based on various events triggered from other submodules like MCPWM Timer, MCPWM Comparator. -- **MCPWM Fault**: The fault module is used to detect the fault condition from outside, mainly via GPIO matrix. Once the fault signal is active, MCPWM Operator will force all the generators into a predefined state, to protect the system from damage. -- **MCPWM Sync**: The sync module is used to synchronize the MCPWM timers, so that the final PWM signals generated by different MCPWM generators can have a fixed phase difference. The sync signal can be routed from GPIO matrix or from MCPWM Timer event. -- **Dead Time**: This submodule is used to insert extra delay to the existing PWM edges that generated in the previous steps. -- **Carrier Modulation**: The carrier submodule allows a high-frequency carrier signal to modulate the PWM waveforms generated by the generator and dead time submodules. This capability is mandatory if you need pulse transformer-based gate drivers to control the power switching elements. -- **Brake**: MCPWM operator can set how to brake the generators when particular fault is detected. We can shut down the PWM output immediately or regulate the PWM output cycle by cycle, depends on how critical the fault is. -- **MCPWM Capture**: This is a standalone submodule which can work even without the above MCPWM operators. The capture consists one dedicated timer and several independent channels. Each channel is connected to the GPIO, a pulse on the GPIO will trigger the capture timer to store the time-base count value and then notify the user by interrupt. Using this feature, we can measure a pulse width precisely. What's more, the capture timer can also be synchronized by the MCPWM Sync submodule. +- **MCPWM Timer**: The time base of the final PWM signal. It also determines the event timing of other submodules. +- **MCPWM Operator**: The key module that is responsible for generating the PWM waveforms. It consists of other submodules, like comparator, PWM generator, dead time, and carrier modulator. +- **MCPWM Comparator**: The compare module takes the time-base count value as input, and continuously compares it to the threshold value configured. When the timer is equal to any of the threshold values, a compare event will be generated and the MCPWM generator can update its level accordingly. +- **MCPWM Generator**: One MCPWM generator can generate a pair of PWM waves, complementarily or independently, based on various events triggered by other submodules like MCPWM Timer and MCPWM Comparator. +- **MCPWM Fault**: The fault module is used to detect the fault condition from outside, mainly via the GPIO matrix. Once the fault signal is active, MCPWM Operator will force all the generators into a predefined state to protect the system from damage. +- **MCPWM Sync**: The sync module is used to synchronize the MCPWM timers, so that the final PWM signals generated by different MCPWM generators can have a fixed phase difference. The sync signal can be routed from the GPIO matrix or from an MCPWM Timer event. +- **Dead Time**: This submodule is used to insert extra delay to the existing PWM edges generated in the previous steps. +- **Carrier Modulation**: The carrier submodule can modulate a high-frequency carrier signal into PWM waveforms by the generator and dead time submodules. This capability is mandatory for controlling the power-switching elements. +- **Brake**: MCPWM operator can set how to brake the generators when a particular fault is detected. We can shut down the PWM output immediately or regulate the PWM output cycle by cycle, depending on how critical the fault is. +- **MCPWM Capture**: This is a standalone submodule that can work even without the above MCPWM operators. The capture consists one dedicated timer and several independent channels, with each channel connected to the GPIO. A pulse on the GPIO will trigger the capture timer to store the time-base count value and then notify you by an interrupt. Using this feature, we can measure a pulse width precisely. What's more, the capture timer can also be synchronized by the MCPWM Sync submodule. Functional Overview ------------------- Description of the MCPWM functionality is divided into the following sections: -- `Resource Allocation and Initialization <#resource-allocation-and-initialization>`__ - covers how to allocate various MCPWM objects, like timers, operators, comparators, generators and so on. These objects are the basis of the following IO setting and control functions. -- `Timer Operations and Events <#timer-operations-and-events>`__ - describes control functions and event callbacks that supported by the MCPWM timer. -- `Comparator Operations and Events <#comparator-operations-and-events>`__ - describes control functions and event callbacks that supported by the MCPWM comparator. -- `Generator Actions on Events <#generator-actions-on-events>`__ - describes how to set actions for MCPWM generators on particular events that generated by the MCPWM timer and comparators. -- `Classical PWM Waveforms and Generator Configurations <#classical-pwm-waveforms-and-generator-configurations>`__ - demonstrates some classical PWM waveforms that can be achieved by configuring generator actions. -- `Dead Time <#dead-time>`__ - describes how to set dead time for MCPWM generators. -- `Classical PWM Waveforms and Dead Time Configurations <#classical-pwm-waveforms-and-dead-time-configurations>`__ - demonstrates some classical PWM waveforms that can be achieved by configuring dead time. -- `Carrier Modulation <#carrier-modulation>`__ - describes how to set modulate a high frequency onto the final PWM waveforms. -- `Faults and Brake Actions <#faults-and-brake-actions>`__ - describes how to set brake actions for MCPWM operators on particular fault event. -- `Generator Force Actions <#generator-force-actions>`__ - describes how to control the generator output level asynchronously in a forceful way. -- `Synchronization <#synchronization>`__ - describes how to synchronize the MCPWM timers and get a fixed phase difference between the generated PWM signals. -- `Capture <#capture>`__ - describes how to use the MCPWM capture module to measure the pulse width of a signal. -- `Power Management <#power-management>`__ - describes how different source clock will affect power consumption. -- `IRAM Safe <#iram-safe>`__ - describes tips on how to make the RMT interrupt work better along with a disabled cache. -- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. -- `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can bring different effects to the driver. +- :ref:`mcpwm-resource-allocation-and-initialization` - covers how to allocate various MCPWM objects, like timers, operators, comparators, generators and so on. These objects are the basis of the following IO setting and control functions. +- :ref:`mcpwm-timer-operations-and-events` - describes control functions and event callbacks supported by the MCPWM timer. +- :ref:`mcpwm-comparator-operations-and-events` - describes control functions and event callbacks supported by the MCPWM comparator. +- :ref:`mcpwm-generator-actions-on-events` - describes how to set actions for MCPWM generators on particular events that are generated by the MCPWM timer and comparators. +- :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - demonstrates some classical PWM waveforms that can be achieved by configuring generator actions. +- :ref:`mcpwm-dead-time` - describes how to set dead time for MCPWM generators. +- :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - demonstrates some classical PWM waveforms that can be achieved by configuring dead time. +- :ref:`mcpwm-carrier-modulation` - describes how to set and modulate a high frequency onto the final PWM waveforms. +- :ref:`mcpwm-faults-and-brake-actions` - describes how to set brake actions for MCPWM operators on particular fault events. +- :ref:`mcpwm-generator-force-actions` - describes how to control the generator output level asynchronously in a forceful way. +- :ref:`mcpwm-synchronization` - describes how to synchronize the MCPWM timers and get a fixed phase difference between the generated PWM signals. +- :ref:`mcpwm-capture` - describes how to use the MCPWM capture module to measure the pulse width of a signal. +- :ref:`mcpwm-power-management` - describes how different source clocks will affect power consumption. +- :ref:`mcpwm-iram-safe` - describes tips on how to make the RMT interrupt work better along with a disabled cache. +- :ref:`mcpwm-thread-safety` - lists which APIs are guaranteed to be thread-safe by the driver. +- :ref:`mcpwm-kconfig-options` - lists the supported Kconfig options that can bring different effects to the driver. + + +.. _mcpwm-resource-allocation-and-initialization: Resource Allocation and Initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,15 +66,15 @@ You can allocate a MCPWM timer object by calling :cpp:func:`mcpwm_new_timer` fun - :cpp:member:`mcpwm_timer_config_t::group_id` specifies the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, timers located in different groups are totally independent. - :cpp:member:`mcpwm_timer_config_t::clk_src` sets the clock source of the timer. -- :cpp:member:`mcpwm_timer_config_t::resolution_hz` set the expected resolution of the timer, the driver internally will set a proper divider based on the clock source and the resolution. +- :cpp:member:`mcpwm_timer_config_t::resolution_hz` sets the expected resolution of the timer. The driver internally will set a proper divider based on the clock source and the resolution. - :cpp:member:`mcpwm_timer_config_t::count_mode` sets the count mode of the timer. - :cpp:member:`mcpwm_timer_config_t::period_ticks` sets the period of the timer, in ticks (the tick resolution is set in the :cpp:member:`mcpwm_timer_config_t::resolution_hz`). - :cpp:member:`mcpwm_timer_config_t::update_period_on_empty` sets whether to update the period value when the timer counts to zero. - :cpp:member:`mcpwm_timer_config_t::update_period_on_sync` sets whether to update the period value when the timer takes a sync signal. -The :cpp:func:`mcpwm_new_timer` will return a pointer to the allocated timer object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no more free timers in the MCPWM group, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_timer` will return a pointer to the allocated timer object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there are no more free timers in the MCPWM group, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ -On the contrary, calling :cpp:func:`mcpwm_del_timer` function will free the allocated timer object. +On the contrary, calling the :cpp:func:`mcpwm_del_timer` function will free the allocated timer object. MCPWM Operators ~~~~~~~~~~~~~~~ @@ -80,170 +86,185 @@ You can allocate a MCPWM operator object by calling :cpp:func:`mcpwm_new_operato - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tep` sets whether to update the generator action when the timer counts to peak. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_sync` sets whether to update the generator action when the timer takes a sync signal. - :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tez` sets whether to update the dead time when the timer counts to zero. -- :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tep` sets whether to update the dead time when the timer counts to peak. +- :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tep` sets whether to update the dead time when the timer counts to the peak. - :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_sync` sets whether to update the dead time when the timer takes a sync signal. -The :cpp:func:`mcpwm_new_operator` will return a pointer to the allocated operator object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no more free operators in the MCPWM group, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_operator` will return a pointer to the allocated operator object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there are no more free operators in the MCPWM group, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ On the contrary, calling :cpp:func:`mcpwm_del_operator` function will free the allocated operator object. MCPWM Comparators ~~~~~~~~~~~~~~~~~ -You can allocate a MCPWM comparator object by calling :cpp:func:`mcpwm_new_comparator` function, with a MCPWM operator handle and configuration structure :cpp:type:`mcpwm_comparator_config_t` as the parameter. The operator handle is created by :cpp:func:`mcpwm_new_operator`. The configuration structure is defined as: +You can allocate a MCPWM comparator object by calling the :cpp:func:`mcpwm_new_comparator` function, with a MCPWM operator handle and configuration structure :cpp:type:`mcpwm_comparator_config_t` as the parameter. The operator handle is created by :cpp:func:`mcpwm_new_operator`. The configuration structure is defined as: - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` sets whether to update the compare threshold when the timer counts to zero. -- :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` sets whether to update the compare threshold when the timer counts to peak. +- :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` sets whether to update the compare threshold when the timer counts to the peak. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync` sets whether to update the compare threshold when the timer takes a sync signal. -The :cpp:func:`mcpwm_new_comparator` will return a pointer to the allocated comparator object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no more free comparators in the MCPWM operator, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_comparator` will return a pointer to the allocated comparator object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there are no more free comparators in the MCPWM operator, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ -On the contrary, calling :cpp:func:`mcpwm_del_comparator` function will free the allocated comparator object. +On the contrary, calling the :cpp:func:`mcpwm_del_comparator` function will free the allocated comparator object. MCPWM Generators ~~~~~~~~~~~~~~~~ -You can allocate a MCPWM generator object by calling :cpp:func:`mcpwm_new_generator` function, with a MCPWM operator handle and configuration structure :cpp:type:`mcpwm_generator_config_t` as the parameter. The operator handle is created by :cpp:func:`mcpwm_new_operator`. The configuration structure is defined as: +You can allocate a MCPWM generator object by calling the :cpp:func:`mcpwm_new_generator` function, with a MCPWM operator handle and configuration structure :cpp:type:`mcpwm_generator_config_t` as the parameter. The operator handle is created by :cpp:func:`mcpwm_new_operator`. The configuration structure is defined as: - :cpp:member:`mcpwm_generator_config_t::gen_gpio_num` sets the GPIO number used by the generator. - :cpp:member:`mcpwm_generator_config_t::invert_pwm` sets whether to invert the PWM signal. -- :cpp:member:`mcpwm_generator_config_t::io_loop_back` sets whether to enable the loop back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. +- :cpp:member:`mcpwm_generator_config_t::io_loop_back` sets whether to enable the Loop-back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. -The :cpp:func:`mcpwm_new_generator` will return a pointer to the allocated generator object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no more free generators in the MCPWM operator, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_generator` will return a pointer to the allocated generator object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there are no more free generators in the MCPWM operator, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ -On the contrary, calling :cpp:func:`mcpwm_del_generator` function will free the allocated generator object. +On the contrary, calling the :cpp:func:`mcpwm_del_generator` function will free the allocated generator object. MCPWM Faults ~~~~~~~~~~~~ -There are two types of faults: A fault signal reflected from the GPIO and a fault generated by software. To allocate a GPIO fault object, you can call :cpp:func:`mcpwm_new_gpio_fault` function, with configuration structure :cpp:type:`mcpwm_gpio_fault_config_t` as the parameter. The configuration structure is defined as: +There are two types of faults: A fault signal reflected from the GPIO and a fault generated by software. -- :cpp:member:`mcpwm_gpio_fault_config_t::group_id` sets the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, GPIO fault located in different groups are totally independent, i.e. GPIO fault in group 0 can not be detected by the operator in group 1. +To allocate a GPIO fault object, you can call the :cpp:func:`mcpwm_new_gpio_fault` function, with the configuration structure :cpp:type:`mcpwm_gpio_fault_config_t` as the parameter. The configuration structure is defined as: + +- :cpp:member:`mcpwm_gpio_fault_config_t::group_id` sets the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, GPIO faults located in different groups are totally independent, i.e., GPIO faults in group 0 can not be detected by the operator in group 1. - :cpp:member:`mcpwm_gpio_fault_config_t::gpio_num` sets the GPIO number used by the fault. - :cpp:member:`mcpwm_gpio_fault_config_t::active_level` sets the active level of the fault signal. - :cpp:member:`mcpwm_gpio_fault_config_t::pull_up` and :cpp:member:`mcpwm_gpio_fault_config_t::pull_down` set whether to pull up and/or pull down the GPIO internally. -- :cpp:member:`mcpwm_gpio_fault_config_t::io_loop_back` sets whether to enable the loop back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. +- :cpp:member:`mcpwm_gpio_fault_config_t::io_loop_back` sets whether to enable the loopback mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. -The :cpp:func:`mcpwm_new_gpio_fault` will return a pointer to the allocated fault object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no more free GPIO faults in the MCPWM group, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_gpio_fault` will return a pointer to the allocated fault object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there are no more free GPIO faults in the MCPWM group, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ -Software fault object can be used to trigger a fault by calling a function :cpp:func:`mcpwm_soft_fault_activate` instead of waiting for a real fault signal on the GPIO. A software fault object can be allocated by calling :cpp:func:`mcpwm_new_soft_fault` function, with configuration structure :cpp:type:`mcpwm_soft_fault_config_t` as the parameter. Currently this configuration structure is left for future purpose. :cpp:func:`mcpwm_new_soft_fault` function will return a pointer to the allocated fault object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no memory left for the fault object, this function will return :c:macro:`ESP_ERR_NO_MEM` error. Although the software fault and GPIO fault are of different types, but the returned fault handle is of the same type. +Software fault object can be used to trigger a fault by calling the function :cpp:func:`mcpwm_soft_fault_activate` instead of waiting for a real fault signal on the GPIO. A software fault object can be allocated by calling the :cpp:func:`mcpwm_new_soft_fault` function, with configuration structure :cpp:type:`mcpwm_soft_fault_config_t` as the parameter. Currently, this configuration structure is left for future purposes. -On the contrary, calling :cpp:func:`mcpwm_del_fault` function will free the allocated fault object, this function works for both software and GPIO fault. +The :cpp:func:`mcpwm_new_soft_fault` function will return a pointer to the allocated fault object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there is no memory left for the fault object, this function will return the :c:macro:`ESP_ERR_NO_MEM` error. Although the software fault and GPIO fault are of different types, the returned fault handle is of the same type. + +On the contrary, calling the :cpp:func:`mcpwm_del_fault` function will free the allocated fault object, this function works for both software and GPIO fault. MCPWM Sync Sources ~~~~~~~~~~~~~~~~~~ -The sync source is what can be used to synchronize the MCPWM timer and MCPWM capture timer. There're three types of sync sources: A sync source reflected from the GPIO, a sync source generated by software and a sync source generated by MCPWM timer event. +The sync source is what can be used to synchronize the MCPWM timer and MCPWM capture timer. There are three types of sync sources: a sync source reflected from the GPIO, a sync source generated by software, and a sync source generated by an MCPWM timer event. -To allocate a GPIO sync source, you can call :cpp:func:`mcpwm_new_gpio_sync_src` function, with configuration structure :cpp:type:`mcpwm_gpio_sync_src_config_t` as the parameter. The configuration structure is defined as: +To allocate a GPIO sync source, you can call the :cpp:func:`mcpwm_new_gpio_sync_src` function, with configuration structure :cpp:type:`mcpwm_gpio_sync_src_config_t` as the parameter. The configuration structure is defined as: -- :cpp:member:`mcpwm_gpio_sync_src_config_t::group_id` sets the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, GPIO sync source located in different groups are totally independent, i.e. GPIO sync source in group 0 can not be detected by the timers in group 1. +- :cpp:member:`mcpwm_gpio_sync_src_config_t::group_id` sets the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. Please note, the GPIO sync sources located in different groups are totally independent, i.e. GPIO sync source in group 0 can not be detected by the timers in group 1. - :cpp:member:`mcpwm_gpio_sync_src_config_t::gpio_num` sets the GPIO number used by the sync source. -- :cpp:member:`mcpwm_gpio_sync_src_config_t::active_neg` sets whether the sync signal is active on falling edge. +- :cpp:member:`mcpwm_gpio_sync_src_config_t::active_neg` sets whether the sync signal is active on negative edges. - :cpp:member:`mcpwm_gpio_sync_src_config_t::pull_up` and :cpp:member:`mcpwm_gpio_sync_src_config_t::pull_down` set whether to pull up and/or pull down the GPIO internally. -- :cpp:member:`mcpwm_gpio_sync_src_config_t::io_loop_back` sets whether to enable the loop back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. +- :cpp:member:`mcpwm_gpio_sync_src_config_t::io_loop_back` sets whether to enable the Loop-back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. -The :cpp:func:`mcpwm_new_gpio_sync_src` will return a pointer to the allocated sync source object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no more free GPIO sync sources in the MCPWM group, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_gpio_sync_src` will return a pointer to the allocated sync source object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there are no more free GPIO sync sources in the MCPWM group, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ -To allocate a Timer event sync source, you can call :cpp:func:`mcpwm_new_timer_sync_src` function, with configuration structure :cpp:type:`mcpwm_timer_sync_src_config_t` as the parameter. The configuration structure is defined as: +To allocate a timer event sync source, you can call the :cpp:func:`mcpwm_new_timer_sync_src` function, with configuration structure :cpp:type:`mcpwm_timer_sync_src_config_t` as the parameter. The configuration structure is defined as: - :cpp:member:`mcpwm_timer_sync_src_config_t::timer_event` specifies on what timer event to generate the sync signal. - :cpp:member:`mcpwm_timer_sync_src_config_t::propagate_input_sync` sets whether to propagate the input sync signal (i.e. the input sync signal will be routed to its sync output). -The :cpp:func:`mcpwm_new_timer_sync_src` will return a pointer to the allocated sync source object if the allocation succeeds. Otherwise, it will return error code. Specifically, if a sync source has been allocated from the same timer before, this function will return :c:macro:`ESP_ERR_INVALID_STATE` error. +The :cpp:func:`mcpwm_new_timer_sync_src` will return a pointer to the allocated sync source object if the allocation succeeds. Otherwise, it will return an error code. Specifically, if a sync source has been allocated from the same timer before, this function will return the :c:macro:`ESP_ERR_INVALID_STATE` error. -Last but not least, to allocate a software sync source, you can call :cpp:func:`mcpwm_new_soft_sync_src` function, with configuration structure :cpp:type:`mcpwm_soft_sync_config_t` as the parameter. Currently this configuration structure is left for future purpose. :cpp:func:`mcpwm_new_soft_sync_src` will return a pointer to the allocated sync source object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no memory left for the sync source object, this function will return :c:macro:`ESP_ERR_NO_MEM` error. Please note, to make a software sync source take effect, don't forget to call :cpp:func:`mcpwm_soft_sync_activate`. +Last but not least, to allocate a software sync source, you can call the :cpp:func:`mcpwm_new_soft_sync_src` function, with configuration structure :cpp:type:`mcpwm_soft_sync_config_t` as the parameter. Currently, this configuration structure is left for future purposes. -On the contrary, calling :cpp:func:`mcpwm_del_sync_src` function will free the allocated sync source object, this function works for all types of sync sources. +:cpp:func:`mcpwm_new_soft_sync_src` will return a pointer to the allocated sync source object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there is no memory left for the sync source object, this function will return the :c:macro:`ESP_ERR_NO_MEM` error. Please note, to make a software sync source take effect, do not forget to call :cpp:func:`mcpwm_soft_sync_activate`. + +On the contrary, calling the :cpp:func:`mcpwm_del_sync_src` function will free the allocated sync source object. This function works for all types of sync sources. MCPWM Capture Timer and Channels ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The MCPWM group has a dedicated timer which is used to capture the timestamp when specific event occurred. The capture timer is connected with several independent channels, each channel is assigned with a GPIO. +The MCPWM group has a dedicated timer which is used to capture the timestamp when a specific event occurred. The capture timer is connected to several independent channels, each channel is assigned a GPIO. -To allocate a capture timer, you can call :cpp:func:`mcpwm_new_capture_timer` function, with configuration structure :cpp:type:`mcpwm_capture_timer_config_t` as the parameter. The configuration structure is defined as: +To allocate a capture timer, you can call the :cpp:func:`mcpwm_new_capture_timer` function, with configuration structure :cpp:type:`mcpwm_capture_timer_config_t` as the parameter. The configuration structure is defined as: - :cpp:member:`mcpwm_capture_timer_config_t::group_id` sets the MCPWM group ID. The ID should belong to [0, :c:macro:`SOC_MCPWM_GROUPS` - 1] range. - :cpp:member:`mcpwm_capture_timer_config_t::clk_src` sets the clock source of the capture timer. -The :cpp:func:`mcpwm_new_capture_timer` will return a pointer to the allocated capture timer object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no free capture timer left in the MCPWM group, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ +The :cpp:func:`mcpwm_new_capture_timer` will return a pointer to the allocated capture timer object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there is no free capture timer left in the MCPWM group, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. [1]_ -Next, to allocate a capture channel, you can call :cpp:func:`mcpwm_new_capture_channel` function, with a capture timer handle and configuration structure :cpp:type:`mcpwm_capture_channel_config_t` as the parameter. The configuration structure is defined as: +Next, to allocate a capture channel, you can call the :cpp:func:`mcpwm_new_capture_channel` function, with a capture timer handle and configuration structure :cpp:type:`mcpwm_capture_channel_config_t` as the parameter. The configuration structure is defined as: - :cpp:member:`mcpwm_capture_channel_config_t::gpio_num` sets the GPIO number used by the capture channel. - :cpp:member:`mcpwm_capture_channel_config_t::prescale` sets the prescaler of the input signal. - :cpp:member:`mcpwm_capture_channel_config_t::pos_edge` and :cpp:member:`mcpwm_capture_channel_config_t::neg_edge` set whether to capture on the positive and/or negative edge of the input signal. - :cpp:member:`mcpwm_capture_channel_config_t::pull_up` and :cpp:member:`mcpwm_capture_channel_config_t::pull_down` set whether to pull up and/or pull down the GPIO internally. - :cpp:member:`mcpwm_capture_channel_config_t::invert_cap_signal` sets whether to invert the capture signal. -- :cpp:member:`mcpwm_capture_channel_config_t::io_loop_back` sets whether to enable the loop back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. +- :cpp:member:`mcpwm_capture_channel_config_t::io_loop_back` sets whether to enable the Loop-back mode. It is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral. -The :cpp:func:`mcpwm_new_capture_channel` will return a pointer to the allocated capture channel object if the allocation succeeds. Otherwise, it will return error code. Specifically, when there are no free capture channel left in the capture timer, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. +The :cpp:func:`mcpwm_new_capture_channel` will return a pointer to the allocated capture channel object if the allocation succeeds. Otherwise, it will return an error code. Specifically, when there is no free capture channel left in the capture timer, this function will return the :c:macro:`ESP_ERR_NOT_FOUND` error. -On the contrary, calling :cpp:func:`mcpwm_del_capture_channel` and :cpp:func:`mcpwm_del_capture_timer` function will free the allocated capture channel and timer object accordingly. +On the contrary, calling :cpp:func:`mcpwm_del_capture_channel` and :cpp:func:`mcpwm_del_capture_timer` will free the allocated capture channel and timer object accordingly. + + +.. _mcpwm-timer-operations-and-events: Timer Operations and Events ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Register Event Callbacks -~~~~~~~~~~~~~~~~~~~~~~~~ +Register Timer Event Callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The MCPWM timer can generate different events at runtime. If you have some function that should be called when particular event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_timer_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_timer_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_timer_event_callbacks_t`: +The MCPWM timer can generate different events at runtime. If you have some function that should be called when a particular event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_timer_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_timer_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_timer_event_callbacks_t`: -- :cpp:member:`mcpwm_timer_event_callbacks_t::on_full` sets callback function for timer when it counts to peak value. -- :cpp:member:`mcpwm_timer_event_callbacks_t::on_empty` sets callback function for timer when it counts to zero. -- :cpp:member:`mcpwm_timer_event_callbacks_t::on_stop` sets callback function for timer when it is stopped. +- :cpp:member:`mcpwm_timer_event_callbacks_t::on_full` sets the callback function for the timer when it counts to peak value. +- :cpp:member:`mcpwm_timer_event_callbacks_t::on_empty` sets the callback function for the timer when it counts to zero. +- :cpp:member:`mcpwm_timer_event_callbacks_t::on_stop` sets the callback function for the timer when it is stopped. -The callback functions above are called within the ISR context, so they should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function). +The callback functions above are called within the ISR context, so they should **not** attempt to block. For example, you may make sure that only FreeRTOS APIs with the ``ISR`` suffix are called within the function. -The parameter ``user_data`` of :cpp:func:`mcpwm_timer_register_event_callbacks` function is used to save user's own context, it will be passed to each callback function directly. +The parameter ``user_data`` of the :cpp:func:`mcpwm_timer_register_event_callbacks` function is used to save your own context. It will be passed to each callback function directly. -This function will lazy install interrupt service for the MCPWM timer without enabling it. It is only allowed to be called before :cpp:func:`mcpwm_timer_enable`, otherwise the :c:macro:`ESP_ERR_INVALID_STATE` error will be returned. See also `Enable and Disable timer <#enable-and-disable-timer>`__ for more information. +This function will lazy the install interrupt service for the MCPWM timer without enabling it. It is only allowed to be called before :cpp:func:`mcpwm_timer_enable`, otherwise the :c:macro:`ESP_ERR_INVALID_STATE` error will be returned. See also `Enable and Disable timer <#enable-and-disable-timer>`__ for more information. Enable and Disable Timer ~~~~~~~~~~~~~~~~~~~~~~~~ -Before doing IO control to the timer, user needs to enable the timer first, by calling :cpp:func:`mcpwm_timer_enable`. Internally, this function will: +Before doing IO control to the timer, you need to enable the timer first, by calling :cpp:func:`mcpwm_timer_enable`. This function will: * switch the timer state from **init** to **enable**. * enable the interrupt service if it has been lazy installed by :cpp:func:`mcpwm_timer_register_event_callbacks`. * acquire a proper power management lock if a specific clock source (e.g. PLL_160M clock) is selected. See also `Power management <#power-management>`__ for more information. -On the contrary, calling :cpp:func:`mcpwm_timer_disable` will put the timer driver back to **init** state, disable the interrupts service and release the power management lock. +On the contrary, calling :cpp:func:`mcpwm_timer_disable` will put the timer driver back to the **init** state, disable the interrupt service and release the power management lock. Start and Stop Timer ~~~~~~~~~~~~~~~~~~~~ -The basic IO operation of a timer is to start and stop. Calling :cpp:func:`mcpwm_timer_start_stop` with different :cpp:type:`mcpwm_timer_start_stop_cmd_t` commands can start the timer immediately or stop the timer at a specific event. What're more, you can even start the timer for only one round, that means, the timer will count to peak value or zero, and then stop itself. +The basic IO operation of a timer is to start and stop. Calling :cpp:func:`mcpwm_timer_start_stop` with different :cpp:type:`mcpwm_timer_start_stop_cmd_t` commands can start the timer immediately or stop the timer at a specific event. What's more, you can even start the timer for only one round, which means, the timer will count to peak value or zero, and then stop itself. Connect Timer with Operator ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The allocated MCPWM Timer should be connected with a MCPWM operator by calling :cpp:func:`mcpwm_operator_connect_timer`, so that the operator can take that timer as its time base, and generate the required PWM waves. Make sure the MCPWM timer and operator are in the same group, otherwise, this function will return :c:macro:`ESP_ERR_INVALID_ARG` error. +The allocated MCPWM timer should be connected with an MCPWM operator by calling :cpp:func:`mcpwm_operator_connect_timer`, so that the operator can take that timer as its time base, and generate the required PWM waves. Please make sure the MCPWM timer and operator are in the same group. Otherwise, this function will return the :c:macro:`ESP_ERR_INVALID_ARG` error. + + +.. _mcpwm-comparator-operations-and-events: Comparator Operations and Events ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Register Event Callbacks -~~~~~~~~~~~~~~~~~~~~~~~~ +Register Comparator Event Callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The MCPWM comparator can inform the user when the timer counter equals to the compare value. If you have some function that should be called when this event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_comparator_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_compare_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_comparator_event_callbacks_t`: +The MCPWM comparator can inform you when the timer counter equals the compare value. If you have some function that should be called when this event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_comparator_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_compare_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_comparator_event_callbacks_t`: -- :cpp:member:`mcpwm_comparator_event_callbacks_t::on_reach` sets callback function for comparator when the timer counter equals to the compare value. +- :cpp:member:`mcpwm_comparator_event_callbacks_t::on_reach` sets the callback function for the comparator when the timer counter equals the compare value. -The callback function will provide event specific data of type :cpp:type:`mcpwm_compare_event_data_t` to the user. The callback function is called within the ISR context, so is should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function). +The callback function will provide event-specific data of type :cpp:type:`mcpwm_compare_event_data_t` to you. The callback function is called within the ISR context, so it should **not** attempt to block. For example, you may make sure that only FreeRTOS APIs with the ``ISR`` suffix are called within the function. -The parameter ``user_data`` of :cpp:func:`mcpwm_comparator_register_event_callbacks` function is used to save user's own context, it will be passed to the callback function directly. +The parameter ``user_data`` of :cpp:func:`mcpwm_comparator_register_event_callbacks` function is used to save your own context. It will be passed to the callback function directly. -This function will lazy install interrupt service for the MCPWM comparator, whereas the service can only be removed in :cpp:type:`mcpwm_del_comparator`. +This function will lazy the installation of interrupt service for the MCPWM comparator, whereas the service can only be removed in :cpp:type:`mcpwm_del_comparator`. Set Compare Value ~~~~~~~~~~~~~~~~~ -You can set the compare value for the MCPWM comparator at runtime by calling :cpp:func:`mcpwm_comparator_set_compare_value`. There're a few points to note: +You can set the compare value for the MCPWM comparator at runtime by calling :cpp:func:`mcpwm_comparator_set_compare_value`. There are a few points to note: -- New compare value might won't take effect immediately. The update time for the compare value is set by :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` or :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` or :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync`. -- Make sure the operator has connected to one MCPWM timer already by :cpp:func:`mcpwm_operator_connect_timer`. Otherwise, it will return error code :c:macro:`ESP_ERR_INVALID_STATE`. -- The compare value shouldn't exceed timer's count peak, otherwise, the compare event will never got triggered. +- A new compare value might not take effect immediately. The update time for the compare value is set by :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` or :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` or :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync`. +- Make sure the operator has connected to one MCPWM timer already by :cpp:func:`mcpwm_operator_connect_timer`. Otherwise, it will return the error code :c:macro:`ESP_ERR_INVALID_STATE`. +- The compare value shouldn't exceed the timer's count peak, otherwise, the compare event will never get triggered. + + +.. _mcpwm-generator-actions-on-events: Generator Actions on Events ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -251,9 +272,9 @@ Generator Actions on Events Set Generator Action on Timer Event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One generator can set multiple actions on different timer events, by calling :cpp:func:`mcpwm_generator_set_actions_on_timer_event` with variable number of action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_timer_event_action_t`: +One generator can set multiple actions on different timer events, by calling :cpp:func:`mcpwm_generator_set_actions_on_timer_event` with a variable number of action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_timer_event_action_t`: -- :cpp:member:`mcpwm_gen_timer_event_action_t::direction` specific the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. +- :cpp:member:`mcpwm_gen_timer_event_action_t::direction` specifies the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. - :cpp:member:`mcpwm_gen_timer_event_action_t::event` specifies the timer event. The supported timer events are listed in :cpp:type:`mcpwm_timer_event_t`. - :cpp:member:`mcpwm_gen_timer_event_action_t::action` specifies the generator action to be taken. The supported actions are listed in :cpp:type:`mcpwm_generator_action_t`. @@ -266,9 +287,9 @@ You can also set the timer action one by one by calling :cpp:func:`mcpwm_generat Set Generator Action on Compare Event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One generator can set multiple actions on different compare events, by calling :cpp:func:`mcpwm_generator_set_actions_on_compare_event` with variable number of action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_compare_event_action_t`: +One generator can set multiple actions on different compare events, by calling :cpp:func:`mcpwm_generator_set_actions_on_compare_event` with a variable number of action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_compare_event_action_t`: -- :cpp:member:`mcpwm_gen_compare_event_action_t::direction` specific the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. +- :cpp:member:`mcpwm_gen_compare_event_action_t::direction` specifies the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. - :cpp:member:`mcpwm_gen_compare_event_action_t::comparator` specifies the comparator handle. See `MCPWM Comparators <#mcpwm-comparators>`__ for how to allocate a comparator. - :cpp:member:`mcpwm_gen_compare_event_action_t::action` specifies the generator action to be taken. The supported actions are listed in :cpp:type:`mcpwm_generator_action_t`. @@ -278,18 +299,21 @@ Please note, the argument list of :cpp:func:`mcpwm_generator_set_actions_on_comp You can also set the compare action one by one by calling :cpp:func:`mcpwm_generator_set_action_on_compare_event` without varargs. -Classical PWM Waveforms and Generator Configurations + +.. _mcpwm-classical-pwm-waveforms-and-generator-configurations: + +Generator Configurations for Classical PWM Waveforms ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This section will demonstrate the classical PWM waveforms that can be generated by the pair of the generators. The code snippet that is used to generate the waveforms is also provided below the diagram. Some general summary: +This section will demonstrate the classical PWM waveforms that can be generated by the pair of generators. The code snippet that is used to generate the waveforms is also provided below the diagram. Some general summary: -- The **Symmetric** or **Asymmetric** of the waveforms are determined by the count mode of the MCPWM timer. +- The **Symmetric** or **Asymmetric** of the waveforms is determined by the count mode of the MCPWM timer. - The **active level** of the waveform pair is determined by the level of the PWM with a smaller duty cycle. - The period of the PWM waveform is determined by the timer's period and count mode. - The duty cycle of the PWM waveform is determined by the generator's various action combinations. -Asymmetric Single Edge Active High -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Single Edge Asymmetric Waveform - Active High +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/single_edge_asym_active_high.json @@ -307,8 +331,8 @@ Asymmetric Single Edge Active High MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW))); } -Asymmetric Single Edge Active Low -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Single Edge Asymmetric Waveform - Active Low +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/single_edge_asym_active_low.json @@ -326,8 +350,8 @@ Asymmetric Single Edge Active Low MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH))); } -Asymmetric Pulse Placement -~~~~~~~~~~~~~~~~~~~~~~~~~~ +Pulse Placement Asymmetric Waveform +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/pulse_placement_asym.json @@ -344,8 +368,8 @@ Asymmetric Pulse Placement MCPWM_GEN_TIMER_EVENT_ACTION_END())); } -Asymmetric Dual Edge Active Low -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Dual Edge Asymmetric Waveform - Active Low +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_asym_active_low.json @@ -363,8 +387,8 @@ Asymmetric Dual Edge Active Low MCPWM_GEN_TIMER_EVENT_ACTION_END())); } -Symmetric Dual Edge Active Low -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Dual Edge Symmetric Waveform - Active Low +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_sym_active_low.json @@ -382,8 +406,8 @@ Symmetric Dual Edge Active Low MCPWM_GEN_COMPARE_EVENT_ACTION_END())); } -Symmetric Dual Edge Complementary -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Dual Edge Symmetric Waveform - Complementary +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_sym_complementary.json @@ -402,26 +426,31 @@ Symmetric Dual Edge Complementary } +.. _mcpwm-dead-time: + Dead Time ^^^^^^^^^ -In power electronics, the rectifier and inverter are commonly used. This requires the use of rectifier bridge and inverter bridge. Each bridge arm has two power electronic devices, such as MOSFET, IGBT, etc. The two MOSFETs on the same arm can't conduct at the same time, otherwise there will be a short circuit. The fact is that, although the PWM wave shows it is turning off the switch, but the MOSFET still needs a small time window to make that happen. This requires an extra delay to be added to the existing PWM wave that generated by setting `Generator Actions on Events <#generator-actions-on-events>`__. +In power electronics, the rectifier and inverter are commonly used. This requires the use of a rectifier bridge and an inverter bridge. Each bridge arm has two power electronic devices, such as MOSFET, IGBT, etc. The two MOSFETs on the same arm can't conduct at the same time, otherwise there will be a short circuit. The fact is that, although the PWM wave shows it is turning off the switch, the MOSFET still needs a small time window to make that happen. This requires an extra delay to be added to the existing PWM wave generated by setting `Generator Actions on Events <#generator-actions-on-events>`__. -The dead-time driver works like a *decorator*, which is also reflected in the function parameters of :cpp:func:`mcpwm_generator_set_dead_time`, where it takes the primary generator handle (``in_generator``), and returns a generator (``out_generator``) after applying the dead-time. Please note, if the ``out_generator`` and ``in_generator`` are the same, it means we're adding the time delay to the PWM waveform in a "in-place" fashion. In turn, if the ``out_generator`` and ``in_generator`` are different, it means we're deriving a new PWM waveform from the existing ``in_generator``. +The dead time driver works like a *decorator*. This is also reflected in the function parameters of :cpp:func:`mcpwm_generator_set_dead_time`, where it takes the primary generator handle (``in_generator``), and returns a generator (``out_generator``) after applying the dead time. Please note, if the ``out_generator`` and ``in_generator`` are the same, it means we are adding the time delay to the PWM waveform in an "in-place" fashion. In turn, if the ``out_generator`` and ``in_generator`` are different, it means we're deriving a new PWM waveform from the existing ``in_generator``. -Dead-time specific configuration is listed in the :cpp:type:`mcpwm_dead_time_config_t` structure: +Dead time specific configuration is listed in the :cpp:type:`mcpwm_dead_time_config_t` structure: -- :cpp:member:`mcpwm_dead_time_config_t::posedge_delay_ticks` and :cpp:member:`mcpwm_dead_time_config_t::negedge_delay_ticks` set the number of ticks to delay the PWM waveform on the rising and falling edge. Specifically, setting both of them to zero means to bypass the dead-time module. The resolution of the dead-time tick is the same to the timer that is connected with the operator by :cpp:func:`mcpwm_operator_connect_timer`. -- :cpp:member:`mcpwm_dead_time_config_t::invert_output`: Whether to invert the signal after applying the dead-time, which can be used to control the delay edge polarity. +- :cpp:member:`mcpwm_dead_time_config_t::posedge_delay_ticks` and :cpp:member:`mcpwm_dead_time_config_t::negedge_delay_ticks` set the number of ticks to delay the PWM waveform on the rising and falling edge. Specifically, setting both of them to zero means bypassing the dead time module. The resolution of the dead time tick is the same as the timer that is connected with the operator by :cpp:func:`mcpwm_operator_connect_timer`. +- :cpp:member:`mcpwm_dead_time_config_t::invert_output` sets whether to invert the signal after applying the dead time, which can be used to control the delay edge polarity. .. note:: - It is also possible to generate the required dead time by setting `Generator Actions on Events <#generator-actions-on-events>`__, especially by controlling edge placement using different comparators. However, if the more classical edge delay-based dead time with polarity control is required, then the dead-time submodule should be used. + It is also possible to generate the required dead time by setting `Generator Actions on Events <#generator-actions-on-events>`__, especially by controlling edge placement using different comparators. However, if the more classical edge delay-based dead time with polarity control is required, then the dead time submodule should be used. -Classical PWM Waveforms and Dead Time Configurations + +.. _mcpwm-classical-pwm-waveforms-and-dead-time-configurations: + +Dead Time Configurations for Classical PWM Waveforms ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This section will demonstrate the classical PWM waveforms that can be generated by the dead-time submodule. The code snippet that is used to generate the waveforms is also provided below the diagram. +This section will demonstrate the classical PWM waveforms that can be generated by the dead time submodule. The code snippet that is used to generate the waveforms is also provided below the diagram. Active High Complementary ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -535,8 +564,8 @@ Active Low ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config)); } -Rising Delay on PWMA, Bypass deadtime for PWMB -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Rising Delay on PWMA and Bypass Dead Time for PWMB +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_reda_bypassb.json @@ -567,8 +596,8 @@ Rising Delay on PWMA, Bypass deadtime for PWMB ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config)); } -Falling Delay on PWMB, Bypass deadtime for PWMA -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Falling Delay on PWMB and Bypass Dead Time for PWMA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_fedb_bypassa.json @@ -600,8 +629,8 @@ Falling Delay on PWMB, Bypass deadtime for PWMA } -Rising and Falling Delay on PWMB, Bypass deadtime for PWMA -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Rising and Falling Delay on PWMB and Bypass Dead Time for PWMA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_redb_fedb_bypassa.json @@ -633,41 +662,47 @@ Rising and Falling Delay on PWMB, Bypass deadtime for PWMA ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config)); } + +.. _mcpwm-carrier-modulation: + Carrier Modulation ^^^^^^^^^^^^^^^^^^ -The MCPWM operator has a carrier submodule that can be used if galvanic isolation from the motor driver is required (e.g. isolated digital power application) by passing the PWM output signals through transformers. Any of PWM output signals may be at 100% duty and not changing whenever motor is required to run steady at the full load. Coupling of non alternating signals with a transformer is problematic, so the signals are modulated by the carrier submodule to create an AC waveform, to make the coupling possible. +The MCPWM operator has a carrier submodule that can be used if galvanic isolation from the motor driver is required (e.g. isolated digital power application) by passing the PWM output signals through transformers. Any of the PWM output signals may be at 100% duty and not changing whenever a motor is required to run steadily at the full load. Coupling with non-alternating signals with a transformer is problematic, so the signals are modulated by the carrier submodule to create an AC waveform, to make the coupling possible. To configure the carrier submodule, you can call :cpp:func:`mcpwm_operator_apply_carrier`, and provide configuration structure :cpp:type:`mcpwm_carrier_config_t`: -- :cpp:member:`mcpwm_carrier_config_t::frequency_hz`: The carrier frequency in Hz. -- :cpp:member:`mcpwm_carrier_config_t::duty_cycle`: The duty cycle of the carrier. Note that, the supported choices of duty cycle are discrete, the driver will search the nearest one based the user configuration. -- :cpp:member:`mcpwm_carrier_config_t::first_pulse_duration_us`: The duration of the first pulse in microseconds. The resolution of the first pulse duration is determined by the carrier frequency you set in the :cpp:member:`mcpwm_carrier_config_t::frequency_hz`. The first pulse duration can't be zero, and it has to be at least one period of the carrier. A longer pulse width can help conduct the inductance quicker. -- :cpp:member:`mcpwm_carrier_config_t::invert_before_modulate` and :cpp:member:`mcpwm_carrier_config_t::invert_after_modulate`: Set whether to invert the carrier output before and after modulation. +- :cpp:member:`mcpwm_carrier_config_t::frequency_hz` indicates carrier frequency in Hz. +- :cpp:member:`mcpwm_carrier_config_t::duty_cycle` indicates the duty cycle of the carrier. Note that, the supported choices of the duty cycle are discrete, the driver will search for the nearest one based on your configuration. +- :cpp:member:`mcpwm_carrier_config_t::first_pulse_duration_us` indicates the duration of the first pulse in microseconds. The resolution of the first pulse duration is determined by the carrier frequency you set in the :cpp:member:`mcpwm_carrier_config_t::frequency_hz`. The first pulse duration can't be zero, and it has to be at least one period of the carrier. A longer pulse width can help conduct the inductance quicker. +- :cpp:member:`mcpwm_carrier_config_t::invert_before_modulate` and :cpp:member:`mcpwm_carrier_config_t::invert_after_modulate` set whether to invert the carrier output before and after modulation. Specifically, the carrier submodule can be disabled by calling :cpp:func:`mcpwm_operator_apply_carrier` with a ``NULL`` configuration. + +.. _mcpwm-faults-and-brake-actions: + Faults and Brake Actions ^^^^^^^^^^^^^^^^^^^^^^^^ -The MCPWM operator is able to sense external signals with information about failure of the motor, the power driver or any other device connected. These failure signals are encapsulated into `MCPWM fault objects <#mcpwm-faults>`__. +The MCPWM operator is able to sense external signals with information about the failure of the motor, the power driver or any other device connected. These failure signals are encapsulated into MCPWM fault objects. -The user should determine possible failure modes of the motor and what action should be performed on detection of particular fault, e.g. drive all outputs low for a brushed motor, or lock current state for a stepper motor, etc. As result of this action the motor should be put into a safe state to reduce likelihood of a damage caused by the fault. +You should determine possible failure modes of the motor and what action should be performed on detection of a particular fault, e.g., drive all outputs low for a brushed motor, lock current state for a stepper motor, etc. As a result of this action, the motor should be put into a safe state to reduce the likelihood of damage caused by the fault. Set Operator Brake Mode on Fault ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The way that MCPWM operator reacts to the fault is called **Brake**. The MCPWM operator can be configured to perform different brake modes for each fault object by calling :cpp:func:`mcpwm_operator_set_brake_on_fault`. Brake specific configuration is passed as a structure :cpp:type:`mcpwm_brake_config_t`: +The way that MCPWM operator reacts to the fault is called **Brake**. The MCPWM operator can be configured to perform different brake modes for each fault object by calling :cpp:func:`mcpwm_operator_set_brake_on_fault`. Specific brake configuration is passed as a structure :cpp:type:`mcpwm_brake_config_t`: -- :cpp:member:`mcpwm_brake_config_t::fault` set which fault that the operator should react to. -- :cpp:member:`mcpwm_brake_config_t::brake_mode` set the brake mode that should be used for the fault. The supported brake modes are listed in the :cpp:type:`mcpwm_operator_brake_mode_t`. For :cpp:enumerator:`MCPWM_OPER_BRAKE_MODE_CBC` mode, the operator will recover itself automatically as long as the fault disappears. You can specify the recovery time in :cpp:member:`mcpwm_brake_config_t::cbc_recover_on_tez` and :cpp:member:`mcpwm_brake_config_t::cbc_recover_on_tep`. For :cpp:enumerator:`MCPWM_OPER_BRAKE_MODE_OST` mode, the operator can't recover even though the fault disappears. User has to call :cpp:func:`mcpwm_operator_recover_from_fault` to manually recover it. +- :cpp:member:`mcpwm_brake_config_t::fault` sets which fault the operator should react to. +- :cpp:member:`mcpwm_brake_config_t::brake_mode` sets the brake mode that should be used for the fault. The supported brake modes are listed in the :cpp:type:`mcpwm_operator_brake_mode_t`. For :cpp:enumerator:`MCPWM_OPER_BRAKE_MODE_CBC` mode, the operator will recover itself automatically as long as the fault disappears. You can specify the recovery time in :cpp:member:`mcpwm_brake_config_t::cbc_recover_on_tez` and :cpp:member:`mcpwm_brake_config_t::cbc_recover_on_tep`. For :cpp:enumerator:`MCPWM_OPER_BRAKE_MODE_OST` mode, the operator can't recover even though the fault disappears. You have to call :cpp:func:`mcpwm_operator_recover_from_fault` to manually recover it. Set Generator Action on Brake Event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One generator can set multiple actions on different brake events, by calling :cpp:func:`mcpwm_generator_set_actions_on_brake_event` with variable number of action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_brake_event_action_t`: +One generator can set multiple actions on different brake events, by calling :cpp:func:`mcpwm_generator_set_actions_on_brake_event` with a variable number of action configurations. The action configuration is defined in :cpp:type:`mcpwm_gen_brake_event_action_t`: -- :cpp:member:`mcpwm_gen_brake_event_action_t::direction` specific the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. +- :cpp:member:`mcpwm_gen_brake_event_action_t::direction` specifies the timer direction. The supported directions are listed in :cpp:type:`mcpwm_timer_direction_t`. - :cpp:member:`mcpwm_gen_brake_event_action_t::brake_mode` specifies the brake mode. The supported brake modes are listed in the :cpp:type:`mcpwm_operator_brake_mode_t`. - :cpp:member:`mcpwm_gen_brake_event_action_t::action` specifies the generator action to be taken. The supported actions are listed in :cpp:type:`mcpwm_generator_action_t`. @@ -680,30 +715,33 @@ You can also set the brake action one by one by calling :cpp:func:`mcpwm_generat Register Fault Event Callbacks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The MCPWM fault detector can inform the user when it detects a valid fault or a fault signal disappears. If you have some function that should be called when such event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_fault_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_fault_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_fault_event_callbacks_t`: +The MCPWM fault detector can inform you when it detects a valid fault or a fault signal disappears. If you have some function that should be called when such an event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_fault_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_fault_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_fault_event_callbacks_t`: -- :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_enter` sets callback function that will be called when a fault is detected. -- :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_exit` sets callback function that will be called when a fault is cleared. +- :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_enter` sets the callback function that will be called when a fault is detected. +- :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_exit` sets the callback function that will be called when a fault is cleared. -The callback function is called within the ISR context, so is should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function). +The callback function is called within the ISR context, so it should **not** attempt to block. For example, you may make sure that only FreeRTOS APIs with the ``ISR`` suffix are called within the function. -The parameter ``user_data`` of :cpp:func:`mcpwm_fault_register_event_callbacks` function is used to save user's own context, it will be passed to the callback function directly. +The parameter ``user_data`` of :cpp:func:`mcpwm_fault_register_event_callbacks` function is used to save your own context. It will be passed to the callback function directly. -This function will lazy install interrupt service for the MCPWM fault, whereas the service can only be removed in :cpp:type:`mcpwm_del_fault`. +This function will lazy the install interrupt service for the MCPWM fault, whereas the service can only be removed in :cpp:type:`mcpwm_del_fault`. Register Brake Event Callbacks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The MCPWM operator can inform the user when it going to take a brake action. If you have some function that should be called when this event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_operator_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_brake_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_operator_event_callbacks_t`: +The MCPWM operator can inform you when it is going to take a brake action. If you have some function that should be called when this event happens, you should hook your function to the interrupt service routine by calling :cpp:func:`mcpwm_operator_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_brake_event_cb_t`. All supported event callbacks are listed in the :cpp:type:`mcpwm_operator_event_callbacks_t`: -- :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_cbc` sets callback function that will be called when the operator is going to take a *CBC* action. -- :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_ost` sets callback function that will be called when the operator is going to take an *OST* action. +- :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_cbc` sets the callback function that will be called when the operator is going to take a *CBC* action. +- :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_ost` sets the callback function that will be called when the operator is going to take an *OST* action. -The callback function is called within the ISR context, so is should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function). +The callback function is called within the ISR context, so it should **not** attempt to block. For example, you may make sure that only FreeRTOS APIs with the ``ISR`` suffix are called within the function. -The parameter ``user_data`` of :cpp:func:`mcpwm_operator_register_event_callbacks` function is used to save user's own context, it will be passed to the callback function directly. +The parameter ``user_data`` of the :cpp:func:`mcpwm_operator_register_event_callbacks` function is used to save your own context. It will be passed to the callback function directly. -This function will lazy install interrupt service for the MCPWM operator, whereas the service can only be removed in :cpp:type:`mcpwm_del_operator`. +This function will lazy the install interrupt service for the MCPWM operator, whereas the service can only be removed in :cpp:type:`mcpwm_del_operator`. + + +.. _mcpwm-generator-force-actions: Generator Force Actions ^^^^^^^^^^^^^^^^^^^^^^^ @@ -711,8 +749,11 @@ Generator Force Actions Software can override generator output level at runtime, by calling :cpp:func:`mcpwm_generator_set_force_level`. The software force level always has a higher priority than other event actions set in e.g. :cpp:func:`mcpwm_generator_set_actions_on_timer_event`. - Set the ``level`` to -1 means to disable the force action, and the generator's output level will be controlled by the event actions again. -- Set the ``hold_on`` to true, the force output level will keep alive, until it's removed by assigning ``level`` to -1. -- Set the ``hole_on`` to false, the force output level will only be active for a short time, any upcoming event can override it. +- Set the ``hold_on`` to true, and the force output level will keep alive until it is removed by assigning ``level`` to -1. +- Set the ``hole_on`` to false, the force output level will only be active for a short time, and any upcoming event can override it. + + +.. _mcpwm-synchronization: Synchronization ^^^^^^^^^^^^^^^ @@ -723,7 +764,7 @@ When a sync signal is taken by the MCPWM timer, the timer will be forced into a - :cpp:member:`mcpwm_timer_sync_phase_config_t::count_value` sets the count value to load when the sync signal is taken. - :cpp:member:`mcpwm_timer_sync_phase_config_t::direction` sets the count direction when the sync signal is taken. -Likewise, the MCPWM capture timer `MCPWM Capture Timer <#mcpwm-capture-timer-and-channels>`__ can be synced as well. You can set the sync phase for the capture timer by calling :cpp:func:`mcpwm_capture_timer_set_phase_on_sync`. The sync phase configuration is defined in :cpp:type:`mcpwm_capture_timer_sync_phase_config_t` structure: +Likewise, the `MCPWM Capture Timer <#mcpwm-capture-timer-and-channels>`__ can be synced as well. You can set the sync phase for the capture timer by calling :cpp:func:`mcpwm_capture_timer_set_phase_on_sync`. The sync phase configuration is defined in :cpp:type:`mcpwm_capture_timer_sync_phase_config_t` structure: - :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::sync_src` sets the sync signal source. See `MCPWM Sync Sources <#mcpwm-sync-sources>`__ for how to create a sync source object. Specifically, if this is set to ``NULL``, the driver will disable the sync feature for the MCPWM capture timer. - :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::count_value` sets the count value to load when the sync signal is taken. @@ -749,7 +790,7 @@ Sync Timers by GPIO .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.active_neg = false, // By default, a posedge pulse can trigger a sync event }; ESP_ERROR_CHECK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_source)); @@ -763,32 +804,34 @@ Sync Timers by GPIO } } + +.. _mcpwm-capture: + Capture ^^^^^^^ -The basic functionality of MCPWM capture is to record the time when any pulse edge of the capture signal turns active. Then you can get the pulse width and convert it into other physical quantity like distance or speed in the capture callback function. For example, in the BLDC (Brushless DC, see figure below) scenario, we can use the capture submodule to sense the rotor position from Hall sensor. +The basic functionality of MCPWM capture is to record the time when any pulse edge of the capture signal turns active. Then you can get the pulse width and convert it into other physical quantities like distance or speed in the capture callback function. For example, in the BLDC (Brushless DC, see figure below) scenario, we can use the capture submodule to sense the rotor position from the Hall sensor. .. figure:: ../../../_static/mcpwm-bldc-control.png :align: center - :alt: Example of Brushless DC Motor Control with MCPWM - :figclass: align-center + :alt: MCPWM BLDC with Hall Sensor MCPWM BLDC with Hall Sensor -The capture timer is usually connected with several capture channels, please refer to `MCPWM Capture Timer and Channels <#mcpwm-capture-timer-and-channels>`__ for resource allocation. +The capture timer is usually connected to several capture channels. Please refer to `MCPWM Capture Timer and Channels <#mcpwm-capture-timer-and-channels>`__ for more information about resource allocation. -Register Event Callbacks -~~~~~~~~~~~~~~~~~~~~~~~~ +Register Capture Event Callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The MCPWM capture channel can inform the user when there's a valid edge detected on the signal. You have to register a callback function to get the timer count value of the capture moment, by calling :cpp:func:`mcpwm_capture_channel_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_capture_event_cb_t`. All supported capture callbacks are listed in the :cpp:type:`mcpwm_capture_event_callbacks_t`: +The MCPWM capture channel can inform you when there's a valid edge detected on the signal. You have to register a callback function to get the timer count value of the captured moment, by calling :cpp:func:`mcpwm_capture_channel_register_event_callbacks`. The callback function prototype is declared in :cpp:type:`mcpwm_capture_event_cb_t`. All supported capture callbacks are listed in the :cpp:type:`mcpwm_capture_event_callbacks_t`: -- :cpp:member:`mcpwm_capture_event_callbacks_t::on_cap` sets callback function for the capture channel when a valid edge is detected. +- :cpp:member:`mcpwm_capture_event_callbacks_t::on_cap` sets the callback function for the capture channel when a valid edge is detected. -The callback function will provide event specific data of type :cpp:type:`mcpwm_capture_event_data_t`, so that you can get the edge of the capture signal in :cpp:member:`mcpwm_capture_event_data_t::cap_edge` and the count value of that moment in :cpp:member:`mcpwm_capture_event_data_t::cap_value`. To convert the capture count into timestamp, you need to know the resolution of the capture timer by calling :cpp:func:`mcpwm_capture_timer_get_resolution`. +The callback function will provide event-specific data of type :cpp:type:`mcpwm_capture_event_data_t`, so that you can get the edge of the capture signal in :cpp:member:`mcpwm_capture_event_data_t::cap_edge` and the count value of that moment in :cpp:member:`mcpwm_capture_event_data_t::cap_value`. To convert the capture count into a timestamp, you need to know the resolution of the capture timer by calling :cpp:func:`mcpwm_capture_timer_get_resolution`. -The callback function is called within the ISR context, so is should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function). +The callback function is called within the ISR context, so it should **not** attempt to block. For example, you may make sure that only FreeRTOS APIs with the ``ISR`` suffix are called within the function. -The parameter ``user_data`` of :cpp:func:`mcpwm_capture_channel_register_event_callbacks` function is used to save user's own context, it will be passed to the callback function directly. +The parameter ``user_data`` of :cpp:func:`mcpwm_capture_channel_register_event_callbacks` function is used to save your context. It will be passed to the callback function directly. This function will lazy install interrupt service for the MCPWM capture channel, whereas the service can only be removed in :cpp:type:`mcpwm_del_capture_channel`. @@ -800,7 +843,7 @@ The capture channel is not enabled after allocation by :cpp:func:`mcpwm_new_capt Enable and Disable Capture Timer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Before doing IO control to the capture timer, user needs to enable the timer first, by calling :cpp:func:`mcpwm_capture_timer_enable`. Internally, this function will: +Before doing IO control to the capture timer, you need to enable the timer first, by calling :cpp:func:`mcpwm_capture_timer_enable`. Internally, this function will: * switch the capture timer state from **init** to **enable**. * acquire a proper power management lock if a specific clock source (e.g. APB clock) is selected. See also `Power management <#power-management>`__ for more information. @@ -815,16 +858,22 @@ The basic IO operation of a capture timer is to start and stop. Calling :cpp:fun Trigger a Software Capture Event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Sometime, the software also wants to trigger a "fake" capture event. The :cpp:func:`mcpwm_capture_channel_trigger_soft_catch` is provided for that purpose. Please note that, even though it's a "fake" capture event, it can still cause an interrupt, thus your capture event callback function will get invoked as well. +Sometimes, the software also wants to trigger a "fake" capture event. The :cpp:func:`mcpwm_capture_channel_trigger_soft_catch` is provided for that purpose. Please note that, even though it's a "fake" capture event, it can still cause an interrupt, thus your capture event callback function will get invoked as well. + + +.. _mcpwm-power-management: Power Management ^^^^^^^^^^^^^^^^ -When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the system will adjust the PLL, APB frequency before going into light sleep, thus potentially changing the period of a MCPWM timers' counting step and leading to inaccurate time keeping. +When power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is on), the system will adjust the PLL and APB frequency before going into Light-sleep, thus potentially changing the period of an MCPWM timers' counting step and leading to inaccurate time-keeping. -However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. Whenever the driver creates a MCPWM timer instance that has selected :cpp:enumerator:`MCPWM_TIMER_CLK_SRC_PLL160M` as its clock source, the driver will guarantee that the power management lock is acquired when enable the timer by :cpp:func:`mcpwm_timer_enable`. Likewise, the driver releases the lock when :cpp:func:`mcpwm_timer_disable` is called for that timer. +However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. Whenever the driver creates an MCPWM timer instance that has selected :cpp:enumerator:`MCPWM_TIMER_CLK_SRC_PLL160M` as its clock source, the driver will guarantee that the power management lock is acquired when enabling the timer by :cpp:func:`mcpwm_timer_enable`. On the contrary, the driver releases the lock when :cpp:func:`mcpwm_timer_disable` is called for that timer. -Likewise, Whenever the driver creates a MCPWM capture timer instance that has selected :cpp:enumerator:`MCPWM_CAPTURE_CLK_SRC_APB` as its clock source, the driver will guarantee that the power management lock is acquired when enable the timer by :cpp:func:`mcpwm_capture_timer_enable`. And will release the lock in :cpp:func:`mcpwm_capture_timer_disable`. +Likewise, whenever the driver creates an MCPWM capture timer instance that has selected :cpp:enumerator:`MCPWM_CAPTURE_CLK_SRC_APB` as its clock source, the driver will guarantee that the power management lock is acquired when enabling the timer by :cpp:func:`mcpwm_capture_timer_enable`. And will release the lock in :cpp:func:`mcpwm_capture_timer_disable`. + + +.. _mcpwm-iram-safe: IRAM Safe ^^^^^^^^^ @@ -833,33 +882,39 @@ By default, the MCPWM interrupt will be deferred when the Cache is disabled for There's a Kconfig option :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE` that will: -1. Enable the interrupt being serviced even when cache is disabled -2. Place all functions that used by the ISR into IRAM [2]_ -3. Place driver object into DRAM (in case it's mapped to PSRAM by accident) +* enable the interrupt to be serviced even when the cache is disabled +* place all functions used by the ISR into IRAM [2]_ +* place the driver object into DRAM (in case it's mapped to PSRAM by accident) This will allow the interrupt to run while the cache is disabled but will come at the cost of increased IRAM consumption. -There is another Kconfig option :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` that can put commonly used IO control functions into IRAM as well. So, these functions can also be executable when the cache is disabled. These IO control functions are as follows: +There is another Kconfig option :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` that can put commonly used IO control functions into IRAM as well. So, these functions can also be executable when the cache is disabled. The IO control function is as follows: - :cpp:func:`mcpwm_comparator_set_compare_value` + +.. _mcpwm-thread-safety: + Thread Safety ^^^^^^^^^^^^^ -The factory functions like :cpp:func:`mcpwm_new_timer` are guaranteed to be thread safe by the driver, which means, you can call it from different RTOS tasks without protection by extra locks. +The factory functions like :cpp:func:`mcpwm_new_timer` are guaranteed to be thread-safe by the driver, which means, you can call it from different RTOS tasks without protection by extra locks. -The following functions are allowed to run under ISR context, as the driver uses a critical section to prevent them being called concurrently in the task and ISR. +The following function is allowed to run under the ISR context, as the driver uses a critical section to prevent them from being called concurrently in the task and ISR. - :cpp:func:`mcpwm_comparator_set_compare_value` -Other functions that are not related to `Resource Allocation <#resource-allocation-and-initialization>`__, are not thread safe. Thus, you should avoid calling them in different tasks without mutex protection. +Other functions that are not related to `Resource Allocation and Initialization <#resource-allocation-and-initialization>`__, are not thread-safe. Thus, you should avoid calling them in different tasks without mutex protection. + + +.. _mcpwm-kconfig-options: Kconfig Options ^^^^^^^^^^^^^^^ -- :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE` controls whether the default ISR handler can work when cache is disabled, see `IRAM Safe <#iram-safe>`__ for more information. -- :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` controls where to place the MCPWM control functions (IRAM or flash), see `IRAM Safe <#iram-safe>`__ for more information. -- :ref:`CONFIG_MCPWM_ENABLE_DEBUG_LOG` is used to enabled the debug log output. Enable this option will increase the firmware binary size. +- :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE` controls whether the default ISR handler can work when the cache is disabled, see :ref:`mcpwm-iram-safe` for more information. +- :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` controls where to place the MCPWM control functions (IRAM or flash), see :ref:`mcpwm-iram-safe` for more information. +- :ref:`CONFIG_MCPWM_ENABLE_DEBUG_LOG` is used to enable the debug log output. Enabling this option will increase the firmware binary size. Application Examples -------------------- @@ -886,7 +941,7 @@ API Reference .. [1] - Different ESP chip series might have different number of MCPWM resources (e.g. groups, timers, comparators, operators, generators and so on). Please refer to the [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__] for details. The driver won't forbid you from applying for more MCPWM resources, but it will return error when there's no hardware resources available. Please always check the return value when doing `Resource Allocation <#resource-allocation-and-initialization>`__. + Different ESP chip series might have a different number of MCPWM resources (e.g. groups, timers, comparators, operators, generators and so on). Please refer to the [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__] for details. The driver won't forbid you from applying for more MCPWM resources, but it will return an error when there are no hardware resources available. Please always check the return value when doing :ref:`mcpwm-resource-allocation-and-initialization`. .. [2] - Callback function and the sub-functions invoked by itself should also be placed in IRAM, users need to take care of this by themselves. + The callback function and the sub-functions invoked by itself should also be placed in IRAM. You need to take care of this by yourself. diff --git a/docs/en/libraries-and-frameworks/index.rst b/docs/en/libraries-and-frameworks/index.rst index de793bedd6..7f6f66b4bc 100644 --- a/docs/en/libraries-and-frameworks/index.rst +++ b/docs/en/libraries-and-frameworks/index.rst @@ -5,5 +5,5 @@ Libraries and Frameworks .. toctree:: :maxdepth: 1 - Cloud Frameworks - Espressif's Libraries and Frameworks + cloud-frameworks + libs-frameworks diff --git a/docs/zh_CN/api-reference/peripherals/mcpwm.rst b/docs/zh_CN/api-reference/peripherals/mcpwm.rst index 368f3c7f86..a120399577 100644 --- a/docs/zh_CN/api-reference/peripherals/mcpwm.rst +++ b/docs/zh_CN/api-reference/peripherals/mcpwm.rst @@ -1 +1,947 @@ -.. include:: ../../../en/api-reference/peripherals/mcpwm.rst +电机控制脉宽调制器 (MCPWM) +=========================================== + +:link_to_translation:`en:[English]` + + +MCPWM 外设是一个多功能 PWM 生成器,集成多个子模块,在电力电子应用(如电机控制、数字电源等)中至关重要。MCPWM 外设通常适用于以下场景: + +- 数字电机控制,如有刷/无刷直流电机、RC 伺服电机 +- 基于开关模式的数字电源转换 +- 功率数模转换器 (Power DAC),其中占空比等于 DAC 的模拟值 +- 计算外部脉宽,并将其转换为其他模拟值,如速度、距离 +- 为磁场定向控制 (FOC) 生成空间矢量调制 (SVPWM) 信号 + +外设的主要子模块如下图所示: + +.. blockdiag:: /../_static/diagrams/mcpwm/mcpwm_overview.diag + :caption: MCPWM 概述 + :align: center + +- **MCPWM 定时器模块**:最终输出 PWM 信号的时间基准。它也决定了其他子模块的事件时序。 +- **MCPWM 操作器模块**:生成 PWM 波形的关键模块。它由其他子模块组成,如比较器、PWM 生成器、死区生成器和载波调制器。 +- **MCPWM 比较器模块**:输入时间基准值,并不断与配置的阈值进行比较。当定时器计数值等于任何一个阈值时,生成一个比较事件,MCPWM 生成器随即相应更新其电平。 +- **MCPWM 生成器模块**:根据 MCPWM 定时器、MCPWM 比较器等子模块触发的各种事件,生成一对独立或互补的 PWM 波形。 +- **MCPWM 故障检测模块**:通过 GPIO 交换矩阵检测外部的故障情况。检测到故障信号时,MCPWM 操作器将强制所有生成器进入预先定义的状态,从而保护系统。 +- **MCPWM 同步模块**:同步 MCPWM 定时器,以确保由不同的 MCPWM 生成器最终生成的 PWM 信号具有固定的相位差。可以通过 GPIO 交换矩阵和 MCPWM 定时器事件生成同步信号。 +- **死区生成器模块**:在此前生成的 PWM 边沿上插入额外的延迟。 +- **载波模块**:可通过 PWM 波形生成器和死区生成器,将一个高频载波信号调制为 PWM 波形,这是控制功率开关器件的必需功能。 +- **制动控制**:MCPWM 操作器支持配置检测到特定故障时生成器的制动控制方式。根据故障的严重程度,可以选择立即关闭或是逐周期调节 PWM 输出。 +- **MCPWM 捕获模块**:独立子模块,不依赖于上述 MCPWM 操作器工作。捕获模块包括一个专用的定时器和几个独立的通道,每个通道都与 GPIO 相连。GPIO 上的脉冲触发捕获定时器以存储时间基准值,随后通过中断进行通知。此模块有助于更加精准地测量脉宽。此外,捕获定时器也可以通过 MCPWM 同步子模块进行同步。 + +功能概述 +------------------- + +下文将分节概述 MCPWM 的功能: + +- :ref:`mcpwm-resource-allocation-and-initialization` - 介绍各类 MCPWM 模块的分配,如定时器、操作器、比较器、生成器等。随后介绍的 IO 设置和控制功能也将围绕这些模块进行。 +- :ref:`mcpwm-timer-operations-and-events` - 介绍 MCPWM 定时器支持的控制功能和事件回调。 +- :ref:`mcpwm-comparator-operations-and-events` - 介绍 MCPWM 比较器支持的控制功能和事件回调。 +- :ref:`mcpwm-generator-actions-on-events` - 介绍如何针对 MCPWM 定时器和比较器生成的特定事件,设置 MCPWM 生成器的相应执行操作。 +- :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - 介绍一些经典 PWM 波形的生成器配置。 +- :ref:`mcpwm-dead-time` - 介绍如何设置 MCPWM 生成器的死区时间。 +- :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - 介绍一些经典 PWM 波形的死区配置。 +- :ref:`mcpwm-carrier-modulation` - 介绍如何在最终输出的 PWM 波形上调制高频载波。 +- :ref:`mcpwm-faults-and-brake-actions` - 介绍如何为 MCPWM 操作器配置特定故障事件下的制动操作。 +- :ref:`mcpwm-generator-force-actions` - 介绍如何强制异步控制生成器的输出水平。 +- :ref:`mcpwm-synchronization` - 介绍如何同步 MCPWM 定时器,并确保生成的最终输出 PWM 信号具有固定的相位差。 +- :ref:`mcpwm-capture` - 介绍如何使用 MCPWM 捕获模块测量信号脉宽。 +- :ref:`mcpwm-power-management` - 介绍不同的时钟源对功耗的影响。 +- :ref:`mcpwm-iram-safe` - 介绍如何协调 RMT 中断与禁用缓存。 +- :ref:`mcpwm-thread-safety` - 列出了由驱动程序认证为线程安全的 API。 +- :ref:`mcpwm-kconfig-options` - 列出了针对驱动的数个 Kconfig 支持选项。 + + +.. _mcpwm-resource-allocation-and-initialization: + +资源配置及初始化 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +如上图所示,MCPWM 外设由数个子模块组成。本节将介绍各个子模块的资源配置方式。 + +MCPWM 定时器 +~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_new_timer` 函数,以配置结构体 :cpp:type:`mcpwm_timer_config_t` 为参数,分配一个 MCPWM 定时器为对象。结构体定义为: + +- :cpp:member:`mcpwm_timer_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的定时器彼此独立。 +- :cpp:member:`mcpwm_timer_config_t::clk_src` 设置定时器的时钟源。 +- :cpp:member:`mcpwm_timer_config_t::resolution_hz` 设置定时器的预期分辨率。内部驱动将根据时钟源和分辨率设置合适的分频器。 +- :cpp:member:`mcpwm_timer_config_t::count_mode` 设置定时器的计数模式。 +- :cpp:member:`mcpwm_timer_config_t::period_ticks` 设置定时器的周期,以 Tick 为单位(通过 :cpp:member:`mcpwm_timer_config_t::resolution_hz` 设置 Tick 分辨率)。 +- :cpp:member:`mcpwm_timer_config_t::update_period_on_empty` 设置当定时器计数为零时是否更新周期值。 +- :cpp:member:`mcpwm_timer_config_t::update_period_on_sync` 设置当定时器接收同步信号时是否更新周期值。 + +分配成功后,:cpp:func:`mcpwm_new_timer` 将返回一个指向已分配定时器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲定时器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +反之,调用 :cpp:func:`mcpwm_del_timer` 函数将释放已分配的定时器。 + +MCPWM 操作器 +~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_new_operator` 函数,以配置结构体 :cpp:type:`mcpwm_operator_config_t` 为参数,分配一个 MCPWM 操作器为对象。结构体定义为: + +- :cpp:member:`mcpwm_operator_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的操作器彼此独立。 +- :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tez` 设置是否在定时器计数为零时更新生成器操作。此处及下文提到的定时器指通过 :cpp:func:`mcpwm_operator_connect_timer` 连接到操作器的定时器。 +- :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tep` 设置当定时器计数达到峰值时是否更新生成器操作。 +- :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_sync` 设置当定时器接收同步信号时是否更新生成器操作。 +- :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tez` 设置当定时器计数为零时是否更新死区时间。 +- :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tep` 设置当定时器计数达到峰值时是否更新死区时间。 +- :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_sync` 设置当定时器接收同步信号时是否更新死区时间。 + +分配成功后,:cpp:func:`mcpwm_new_operator` 将返回一个指向已分配操作器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲操作器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +反之,调用 :cpp:func:`mcpwm_del_operator` 函数将释放已分配的操作器。 + +MCPWM 比较器 +~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_new_comparator` 函数,以一个 MCPWM 操作器句柄和配置结构体 :cpp:type:`mcpwm_comparator_config_t` 为参数,分配一个 MCPWM 比较器为对象。操作器句柄由 :cpp:func:`mcpwm_new_operator` 生成,结构体定义为: + +- :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` 设置当定时器计数为零时是否更新比较阈值。 +- :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` 设置当定时器计数达到峰值时是否更新比较阈值。 +- :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync` 设置当定时器接收同步信号时是否更新比较阈值。 + +分配成功后,:cpp:func:`mcpwm_new_comparator` 将返回一个指向已分配比较器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 操作器中没有空闲比较器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +反之,调用 :cpp:func:`mcpwm_del_comparator` 函数将释放已分配的比较器。 + +MCPWM 生成器 +~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_new_generator` 函数,以一个 MCPWM 操作器句柄和配置结构体 :cpp:type:`mcpwm_generator_config_t` 为参数,分配一个 MCPWM 生成器为对象。操作器句柄由 :cpp:func:`mcpwm_new_operator` 生成,结构体定义为: + +- :cpp:member:`mcpwm_generator_config_t::gen_gpio_num` 设置生成器使用的 GPIO 编号。 +- :cpp:member:`mcpwm_generator_config_t::invert_pwm` 设置是否反相 PWM 信号。 +- :cpp:member:`mcpwm_generator_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。 + +分配成功后,:cpp:func:`mcpwm_new_generator` 将返回一个指向已分配生成器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 操作器中没有空闲生成器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +反之,调用 :cpp:func:`mcpwm_del_generator` 函数将释放已分配的生成器。 + +MCPWM 故障 +~~~~~~~~~~~~ + +MCPWM 故障分为两种类型:来自 GPIO 的故障信号和软件故障。 + +调用 :cpp:func:`mcpwm_new_gpio_fault` 函数,以配置结构体 :cpp:type:`mcpwm_gpio_fault_config_t` 为参数,分配一个 GPIO 故障为对象。结构体定义为: + +- :cpp:member:`mcpwm_gpio_fault_config_t::group_id` 设置 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的 GPIO 故障彼此独立,也就是说,1 组的操作器无法检测到 0 组的 GPIO 故障。 +- :cpp:member:`mcpwm_gpio_fault_config_t::gpio_num` 设置故障所使用的 GPIO 编号。 +- :cpp:member:`mcpwm_gpio_fault_config_t::active_level` 设置故障信号的有效电平。 +- :cpp:member:`mcpwm_gpio_fault_config_t::pull_up` 和 :cpp:member:`mcpwm_gpio_fault_config_t::pull_down` 设置是否在内部拉高和/或拉低 GPIO。 +- :cpp:member:`mcpwm_gpio_fault_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。 + +分配成功后,:cpp:func:`mcpwm_new_gpio_fault` 将返回一个指向已分配故障的指针。否则,函数将返回错误代码。具体来说,当指定 MCPWM 组中没有空闲 GPIO 故障时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +调用函数 :cpp:func:`mcpwm_soft_fault_activate` 使一个软件故障对象触发故障,无需等待来自 GPIO 的真实故障信号。调用 :cpp:func:`mcpwm_new_soft_fault` 函数,以配置结构体 :cpp:type:`mcpwm_soft_fault_config_t` 为参数,分配一个软件故障为对象。该结构体暂时保留,供后续使用。 + +分配成功后,:cpp:func:`mcpwm_new_soft_fault` 将返回一个指向已分配故障的指针。否则,函数将返回错误代码。具体来说,当内存不足以支持该故障对象时,将返回 :c:macro:`ESP_ERR_NO_MEM` 错误。虽然软件故障和 GPIO 故障是不同类型的故障,但返回的故障句柄为同一类型。 + +反之,调用 :cpp:func:`mcpwm_del_fault` 函数将释放已分配的故障。此函数同时适用于软件故障和 GPIO 故障。 + +MCPWM 同步源 +~~~~~~~~~~~~~~~~~~ + +同步源用于同步 MCPWM 定时器和 MCPWM 捕获定时器,分为三种类型:来自 GPIO 的同步源、软件生成的同步源和 MCPWM 定时器事件生成的同步源。 + +调用 :cpp:func:`mcpwm_new_gpio_sync_src` 函数,以配置结构体 :cpp:type:`mcpwm_gpio_sync_src_config_t` 为参数,分配一个 GPIO 同步源。结构体定义为: + +- :cpp:member:`mcpwm_gpio_sync_src_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的 GPIO 同步源彼此独立,也就是说,1 组的定时器无法检测到 0 组的 GPIO 同步源。 +- :cpp:member:`mcpwm_gpio_sync_src_config_t::gpio_num` 设置同步源使用的 GPIO 编号。 +- :cpp:member:`mcpwm_gpio_sync_src_config_t::active_neg` 设置同步信号在下降沿是否有效。 +- :cpp:member:`mcpwm_gpio_sync_src_config_t::pull_up` 和 :cpp:member:`mcpwm_gpio_sync_src_config_t::pull_down` 设置是否在内部拉高和/或拉低 GPIO。 +- :cpp:member:`mcpwm_gpio_sync_src_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。 + +分配成功后,:cpp:func:`mcpwm_new_gpio_sync_src` 将返回一个指向已分配同步源的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲 GPIO 时钟源时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +调用 :cpp:func:`mcpwm_new_timer_sync_src` 函数,以配置结构体 :cpp:type:`mcpwm_timer_sync_src_config_t` 为参数,分配一个定时器事件同步源。结构体定义为: + +- :cpp:member:`mcpwm_timer_sync_src_config_t::timer_event` 指定产生同步信号的定时器事件。 +- :cpp:member:`mcpwm_timer_sync_src_config_t::propagate_input_sync` 是否广播输入同步信号(即将输入同步信号传输到其同步输出)。 + +分配成功后,:cpp:func:`mcpwm_new_timer_sync_src` 将返回一个指向已分配同步源的指针。否则,函数将返回错误代码。具体来说,若是分配的同步源此前已分配给了同一个定时器,将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。 + +也可以调用 :cpp:func:`mcpwm_new_soft_sync_src` 函数,以配置结构体 :cpp:type:`mcpwm_soft_sync_config_t` 为参数,分配一个软件同步源。该结构体暂时保留,供后续使用。 + +分配成功后,:cpp:func:`mcpwm_new_soft_sync_src` 将返回一个指向已分配同步源的指针。否则,函数将返回错误代码。具体来说,当内存不足以支持分配的同步源时,将返回 :c:macro:`ESP_ERR_NO_MEM` 错误。需注意,为确保软件同步源能够正常工作,应预先调用 :cpp:func:`mcpwm_soft_sync_activate`。 + +相反,调用 :cpp:func:`mcpwm_del_sync_src` 函数将释放分配的同步源对象。此函数适用于所有类型的同步源。 + +MCPWM 捕获定时器和通道 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 组有一个专用定时器,用于捕获特定事件发生时的时间戳。捕获定时器连接了数个独立通道,每个通道都分配了各自的 GPIO。 + +调用 :cpp:func:`mcpwm_new_capture_timer` 函数,以配置结构体 :cpp:type:`mcpwm_capture_timer_config_t` 为参数,分配一个捕获定时器。结构体定义为: + +- :cpp:member:`mcpwm_capture_timer_config_t::group_id` 设置 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。 +- :cpp:member:`mcpwm_capture_timer_config_t::clk_src` 设置捕获定时器的时钟源。 + +分配成功后,:cpp:func:`mcpwm_new_capture_timer` 将返回一个指向已分配捕获定时器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲捕获定时器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_ + +接下来,可以调用 :cpp:func:`mcpwm_new_capture_channel` 函数,以一个捕获定时器句柄和配置结构体 :cpp:type:`mcpwm_capture_channel_config_t` 为参数,分配一个捕获通道。结构体定义为: + +- :cpp:member:`mcpwm_capture_channel_config_t::gpio_num` 设置捕获通道使用的 GPIO 编号。 +- :cpp:member:`mcpwm_capture_channel_config_t::prescale` 设置输入信号的预分频器。 +- :cpp:member:`mcpwm_capture_channel_config_t::pos_edge` 和 :cpp:member:`mcpwm_capture_channel_config_t::neg_edge` 设置是否在输入信号的上升沿和/或下降沿捕获时间戳。 +- :cpp:member:`mcpwm_capture_channel_config_t::pull_up` 和 :cpp:member:`mcpwm_capture_channel_config_t::pull_down` 设置是否在内部拉高和/或拉低 GPIO。 +- :cpp:member:`mcpwm_capture_channel_config_t::invert_cap_signal` 设置是否取反捕获信号。 +- :cpp:member:`mcpwm_capture_channel_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。 + +分配成功后,:cpp:func:`mcpwm_new_capture_channel` 将返回一个指向已分配捕获通道的指针。否则,函数将返回错误代码。具体来说,当捕获定时器中没有空闲捕获通道时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。 + +反之,调用 :cpp:func:`mcpwm_del_capture_channel` 和 :cpp:func:`mcpwm_del_capture_timer` 将释放已分配的捕获通道和定时器。 + + +.. _mcpwm-timer-operations-and-events: + +定时器操作和事件 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +注册定时器事件回调 +~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 定时器运行时会生成不同的事件。若有函数需在特定事件发生时调用,则应预先调用 :cpp:func:`mcpwm_timer_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中定时器回调函数原型声明为 :cpp:type:`mcpwm_timer_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_timer_event_callbacks_t` 中: + +- :cpp:member:`mcpwm_timer_event_callbacks_t::on_full` 设置定时器计数达到峰值时的回调函数。 +- :cpp:member:`mcpwm_timer_event_callbacks_t::on_empty` 设置定时器计数为零时的回调函数。 +- :cpp:member:`mcpwm_timer_event_callbacks_t::on_stop` 设置定时器停止时的回调函数。 + +由于上述回调函数是在 ISR 中调用的,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。 + +函数 :cpp:func:`mcpwm_timer_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。 + +此函数会在不启用 MCPWM 定时器的情况下延迟安装其中断服务。因此,需在调用 :cpp:func:`mcpwm_timer_enable` 函数前调用该函数,否则将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。更多信息请参见 `启用和禁用定时器`_。 + +启用和禁用定时器 +~~~~~~~~~~~~~~~~~~~~~~~~ + +在对定时器进行 IO 控制前,需要预先调用 :cpp:func:`mcpwm_timer_enable` 函数启用定时器。这个函数将: + +* 将定时器的状态从 **init** 切换到 **enable**。 +* 若中断服务此前已通过 :cpp:func:`mcpwm_timer_register_event_callbacks` 函数延迟安装,则启用中断服务。 +* 若选择了特定时钟源(例如 PLL_160M 时钟),则获取相应的电源管理锁。更多信息请参见 `电源管理`_。 + +反之,调用 :cpp:func:`mcpwm_timer_disable` 会将定时器切换回 **init** 状态、禁用中断服务并释放电源管理锁。 + +启动和停止定时器 +~~~~~~~~~~~~~~~~~~~~ + +通过基本的 IO 控制,即可启动和停止定时器。使用不同的 :cpp:type:`mcpwm_timer_start_stop_cmd_t` 命令调用 :cpp:func:`mcpwm_timer_start_stop` 便可立即启动定时器,或在发生特定事件时停止定时器。此外,还可以通过配置,让定时器仅计数一轮。也就是说,在计数达到峰值或零后,定时器自行停止。 + +连接定时器和操作器 +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_operator_connect_timer` 函数,连接分配的 MCPWM 定时器和 MCPWM 操作器。连接后,操作器即可将定时器作为时基,生成所需的 PWM 波形。需注意,MCPWM 定时器和操作器必须位于同一个组中。否则,将返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。 + + +.. _mcpwm-comparator-operations-and-events: + +比较器操作和事件 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +注册比较器事件回调 +~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 比较器可以在定时器计数器等于比较值时发送通知。若有函数需在比较事件发生时调用,则应预先调用 :cpp:func:`mcpwm_comparator_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中比较器回调函数原型声明为 :cpp:type:`mcpwm_compare_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_comparator_event_callbacks_t` 中: + +- :cpp:member:`mcpwm_comparator_event_callbacks_t::on_reach` 设置当定时器计数器等于比较值时的比较器回调函数。 + +回调函数会提供类型为 :cpp:type:`mcpwm_compare_event_data_t` 的事件特定数据。由于上述回调函数是在 ISR 中调用的,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。 + +函数 :cpp:func:`mcpwm_comparator_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。 + +此函数会延迟安装 MCPWM 比较器的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_comparator` 移除。 + +设置比较值 +~~~~~~~~~~~~~~~~~ + +运行 MCPWM 比较器时,可以调用 :cpp:func:`mcpwm_comparator_set_compare_value` 设置比较值。需注意以下几点: + +- 重新设置的比较值可能不会立即生效。比较值的更新时间通过 :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` 或 :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` 或 :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync` 配置。 +- 请确保已经预先调用 :cpp:func:`mcpwm_operator_connect_timer` 将操作器连接至 MCPWM 定时器。否则,将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。 +- 比较值不应超过定时器的计数峰值。否则,将无法触发比较事件。 + + +.. _mcpwm-generator-actions-on-events: + +生成器对事件执行的操作 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +设置生成器对定时器事件执行的操作 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_generator_set_actions_on_timer_event` 并辅以若干操作配置,可以针对不同的定时器事件,为生成器设置不同的操作。操作配置定义在 :cpp:type:`mcpwm_gen_timer_event_action_t` 中: + +- :cpp:member:`mcpwm_gen_timer_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。 +- :cpp:member:`mcpwm_gen_timer_event_action_t::event` 指定定时器事件,可以调用 :cpp:type:`mcpwm_timer_event_t` 查看支持的定时器事件。 +- :cpp:member:`mcpwm_gen_timer_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。 + +可借助辅助宏 :c:macro:`MCPWM_GEN_TIMER_EVENT_ACTION` 构建定时器事件操作条目。 + +需注意,:cpp:func:`mcpwm_generator_set_actions_on_timer_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_TIMER_EVENT_ACTION_END` 结束。 + +也可以调用 :cpp:func:`mcpwm_generator_set_action_on_timer_event` 逐一设置定时器操作,无需涉及变量参数。 + +设置生成器对比较器事件执行的操作 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_generator_set_actions_on_compare_event` 并辅以若干操作配置,可以针对不同的比较器事件,为生成器设置不同的操作。操作配置定义在 :cpp:type:`mcpwm_gen_compare_event_action_t` 中: + +- :cpp:member:`mcpwm_gen_compare_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。 +- :cpp:member:`mcpwm_gen_compare_event_action_t::comparator` 指定比较器句柄。有关分配比较器的方法,请参见 `MCPWM 比较器`_。 +- :cpp:member:`mcpwm_gen_compare_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。 + +可借助辅助宏 :c:macro:`MCPWM_GEN_COMPARE_EVENT_ACTION` 构建比较事件操作条目。 + +需注意,:cpp:func:`mcpwm_generator_set_actions_on_compare_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_COMPARE_EVENT_ACTION_END` 结束。 + +也可以调用 :cpp:func:`mcpwm_generator_set_action_on_compare_event` 逐一设置定时器操作,无需涉及变量参数。 + + +.. _mcpwm-classical-pwm-waveforms-and-generator-configurations: + +经典 PWM 波形的生成器配置 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +本节提供了一些生成器支持生成的经典 PWM 波形,同时提供用于生成这些波形的代码片段。总的来说: + +- 生成波形为 **对称波形** 还是 **不对称波形** 取决于 MCPWM 定时器的计数模式。 +- 波形对的 **激活电平** 取决于占空比较小的 PWM 波形的电平。 +- PWM 波形的周期取决于定时器的周期和计数模式。 +- PWM 波形的占空比取决于生成器的各种操作配置组合。 + +单边不对称波形 - 高电平 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/single_edge_asym_active_high.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW))); + } + +单边不对称波形 - 低电平 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/single_edge_asym_active_low.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH))); + } + +脉冲位置不对称波形 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/pulse_placement_asym.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_COMPARE_EVENT_ACTION_END())); + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_TOGGLE), + MCPWM_GEN_TIMER_EVENT_ACTION_END())); + } + +双沿不对称波形 - 低电平有效 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_asym_active_low.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_COMPARE_EVENT_ACTION_END())); + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_TIMER_EVENT_ACTION_END())); + } + +双沿对称波形 - 低电平有效 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_sym_active_low.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_COMPARE_EVENT_ACTION_END())); + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_COMPARE_EVENT_ACTION_END())); + } + +双沿对称波形 - 互补 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_sym_complementary.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_COMPARE_EVENT_ACTION_END())); + ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW), + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_HIGH), + MCPWM_GEN_COMPARE_EVENT_ACTION_END())); + } + + +.. _mcpwm-dead-time: + +死区 +^^^^^^^^^ + +在电力电子学中,常常会用到整流器和逆变器,这就涉及到了整流桥和逆变桥的应用。每个桥臂配有两个功率电子器件,例如 MOSFET、IGBT 等。同一桥臂上的两个 MOSFET 不能同时导通,否则会造成短路。实际应用中,在 PWM 波形显示 MOSFET 开关已关闭后,仍需要一段时间窗口才能完全关闭 MOSFET。因此,需要设置 :ref:`mcpwm-generator-actions-on-events`,在已生成的 PWM 波形上添加额外延迟。 + +死区驱动器的工作方式与 *装饰器* 类似。在 :cpp:func:`mcpwm_generator_set_dead_time` 函数的参数中,驱动接收主要生成器句柄 (``in_generator``),并在应用死区后返回一个新的生成器 (``out_generator``)。需注意,如果 ``out_generator`` 和 ``in_generator`` 相同,这表示 PWM 波形中的时间延迟是以“就地”的方式添加的。反之,如果 ``out_generator`` 和 ``in_generator`` 不同,则代表在原 ``in_generator`` 的基础上派生出了一个新的 PWM 波形。 + +结构体 :cpp:type:`mcpwm_dead_time_config_t` 中列出了死区相关的具体配置: + +- :cpp:member:`mcpwm_dead_time_config_t::posedge_delay_ticks` 和 :cpp:member:`mcpwm_dead_time_config_t::negedge_delay_ticks` 设置 PWM 波形上升沿和下降沿上的延迟时间,以 Tick 为单位。若将这两个参数设置为 0,则代表绕过死区模块。死区的 Tick 分辨率与通过 :cpp:func:`mcpwm_operator_connect_timer` 连接操作器的定时器相同。 +- :cpp:member:`mcpwm_dead_time_config_t::invert_output` 设置是否在应用死区后取反信号,以控制延迟边沿的极性。 + +.. note:: + + 也可以通过设置 :ref:`mcpwm-generator-actions-on-events` 来生成所需的死区,通过不同的比较器来控制边沿位置。但是,如果需要使用经典的基于边沿延迟并附带极性控制的死区,则应使用死区子模块。 + + +.. _mcpwm-classical-pwm-waveforms-and-dead-time-configurations: + +经典 PWM 波形的死区配置 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +本节提供了一些死区子模块支持生成的经典 PWM 波形,同时在图片下方提供用于生成这些波形的代码片段。 + +高电平有效互补 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_high_complementary.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 50, + .negedge_delay_ticks = 0 + }; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + dead_time_config.posedge_delay_ticks = 0; + dead_time_config.negedge_delay_ticks = 100; + dead_time_config.flags.invert_output = true; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config)); + } + +低电平有效互补 +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_low_complementary.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 50, + .negedge_delay_ticks = 0, + .flags.invert_output = true + }; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + dead_time_config.posedge_delay_ticks = 0; + dead_time_config.negedge_delay_ticks = 100; + dead_time_config.flags.invert_output = false; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config)); + } + +高电平有效 +~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_high.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 50, + .negedge_delay_ticks = 0, + }; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + dead_time_config.posedge_delay_ticks = 0; + dead_time_config.negedge_delay_ticks = 100; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config)); + } + +低电平有效 +~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_low.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 50, + .negedge_delay_ticks = 0, + .flags.invert_output = true + }; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + dead_time_config.posedge_delay_ticks = 0; + dead_time_config.negedge_delay_ticks = 100; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config)); + } + +PWMA 上升沿延迟,绕过 PWMB 死区 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_reda_bypassb.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 50, + .negedge_delay_ticks = 0, + }; + // apply deadtime to generator_a + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + // bypass deadtime module for generator_b + dead_time_config.posedge_delay_ticks = 0; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config)); + } + +PWMB 下降沿延迟,绕过 PWMA 死区 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_fedb_bypassa.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 0, + .negedge_delay_ticks = 0, + }; + // generator_a bypass the deadtime module (no delay) + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + // apply dead time to generator_b + dead_time_config.negedge_delay_ticks = 50; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config)); + + } + +PWMB 上升下降沿延迟,绕过 PWMA 死区 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. wavedrom:: /../_static/diagrams/mcpwm/deadtime_redb_fedb_bypassa.json + +.. code:: c + + static void gen_action_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb) + { + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb, + MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH))); + ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb, + MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW))); + } + + static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb) + { + mcpwm_dead_time_config_t dead_time_config = { + .posedge_delay_ticks = 0, + .negedge_delay_ticks = 0, + }; + // generator_a bypass the deadtime module (no delay) + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config)); + // apply dead time on both edge for generator_b + dead_time_config.negedge_delay_ticks = 50; + dead_time_config.posedge_delay_ticks = 50; + ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config)); + } + + +.. _mcpwm-carrier-modulation: + +载波调制 +^^^^^^^^^^^^^^^^^^ + +MCPWM 操作器具有载波子模块,可以根据需要(例如隔离式数字电源应用中)使用变压器传递 PWM 输出信号,实现电机驱动器的电气隔离。在电机需要在全负荷下稳定运行时,各个 PWM 输出信号都将占空比稳定保持在 100% 左右。由于变压器无法直接耦合非交替信号,需要使用载波子模块调制信号,生成交流电波形,从而实现耦合。 + +调用 :cpp:func:`mcpwm_operator_apply_carrier`,并提供配置结构体 :cpp:type:`mcpwm_carrier_config_t`,配置载波子模块: + +- :cpp:member:`mcpwm_carrier_config_t::frequency_hz` 表示载波频率,单位为赫兹。 +- :cpp:member:`mcpwm_carrier_config_t::duty_cycle` 表示载波的占空比。需注意,支持的占空比选项并不连续,驱动程序将根据配置查找最接近的占空比。 +- :cpp:member:`mcpwm_carrier_config_t::first_pulse_duration_us` 表示第一个脉冲的脉宽,单位为微秒。该脉冲的分辨率由 :cpp:member:`mcpwm_carrier_config_t::frequency_hz` 中的配置决定。第一个脉冲的脉宽不能为零,且至少为一个载波周期。脉宽越长,电感传导越快。 +- :cpp:member:`mcpwm_carrier_config_t::invert_before_modulate` 和 :cpp:member:`mcpwm_carrier_config_t::invert_after_modulate` 设置是否在调制前和调制后取反载波输出。 + +具体而言,可调用 :cpp:func:`mcpwm_operator_apply_carrier` 并将其配置为 ``NULL``,禁用载波子模块。 + + +.. _mcpwm-faults-and-brake-actions: + +故障检测和制动控制 +^^^^^^^^^^^^^^^^^^^^^^^^ + +MCPWM 操作器能够感知外部信号,接收有关电机故障、功率驱动器及其他连接设备的信息。这些故障信号封装在 MCPWM 故障对象中。 + +电机需配置故障模式以及检测到特定故障时的对应操作,例如拉低有刷电机的所有输出,或是锁定步进电机的电流状态等。此操作应使电机重回安全状态,降低故障导致损坏的可能性。 + +设置故障时操作器的制动模式 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 操作器对故障的响应方式为 **制动**。可以调用 :cpp:func:`mcpwm_operator_set_brake_on_fault`,为每个故障对象配置不同的制动模式。制动的相关配置包含在结构体 :cpp:type:`mcpwm_brake_config_t` 中: + +- :cpp:member:`mcpwm_brake_config_t::fault` 设置操作器响应的故障类型。 +- :cpp:member:`mcpwm_brake_config_t::brake_mode` 设置对应故障的制动模式,可以调用 :cpp:type:`mcpwm_operator_brake_mode_t` 查看支持的制动模式。在 :cpp:enumerator:`MCPWM_OPER_BRAKE_MODE_CBC` 模式下,操作器将在故障消失后自行恢复正常,可以通过 :cpp:member:`mcpwm_brake_config_t::cbc_recover_on_tez` 和 :cpp:member:`mcpwm_brake_config_t::cbc_recover_on_tep` 配置恢复时间。在 :cpp:enumerator:`MCPWM_OPER_BRAKE_MODE_OST` 模式下,即使故障消失,操作器也无法恢复正常。此时,需要调用 :cpp:func:`mcpwm_operator_recover_from_fault`,手动恢复操作器。 + +设置发生制动事件时的生成器操作 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_generator_set_actions_on_brake_event` 并辅以若干操作配置,可以针对不同的制动事件,为生成器设置不同的对应操作。操作配置定义在 :cpp:type:`mcpwm_gen_brake_event_action_t` 中: + +- :cpp:member:`mcpwm_gen_brake_event_action_t::direction` 指定定时器的方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。 +- :cpp:member:`mcpwm_gen_brake_event_action_t::brake_mode` 指定制动模式,可以调用 :cpp:type:`mcpwm_operator_brake_mode_t` 查看支持的制动模式。 +- :cpp:member:`mcpwm_gen_brake_event_action_t::action` 指定生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。 + +可借助辅助宏 :c:macro:`MCPWM_GEN_BRAKE_EVENT_ACTION` 构建制动事件操作条目。 + +需注意, :cpp:func:`mcpwm_generator_set_actions_on_brake_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_BRAKE_EVENT_ACTION_END` 结束。 + +也可以调用 :cpp:func:`mcpwm_generator_set_action_on_brake_event` 逐一设置制动操作,无需涉及变量参数。 + +注册故障事件回调 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 故障检测器支持在检测到实际故障或故障信号消失时发送通知。若有函数需在特定事件发生时调用,则应预先调用 :cpp:func:`mcpwm_fault_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中故障事件回调函数原型声明为 :cpp:type:`mcpwm_fault_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_fault_event_callbacks_t` 中: + +- :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_enter` 设置检测到故障时调用的回调函数。 +- :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_exit` 设置故障消失后调用的回调函数。 + +由于上述回调函数在 ISR 中调用,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。 + +函数 :cpp:func:`mcpwm_fault_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。 + +此函数会延迟安装 MCPWM 故障的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_fault` 移除。 + +寄存器制动事件回调 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 操作器支持在进行制动操作前发送通知。若有函数需在特定事件发生时调用,则应预先调用 :cpp:func:`mcpwm_operator_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中制动事件回调函数原型声明为 :cpp:type:`mcpwm_brake_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_operator_event_callbacks_t` 中: + +- :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_cbc` 设置操作器进行 *逐周期 (CBC)* 操作前调用的回调函数。 +- :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_ost` 设置操作器进行 *一次性 (OST)* 操作前调用的回调函数。 + +由于上述回调函数在 ISR 中调用,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。 + +函数 :cpp:func:`mcpwm_operator_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。 + +此函数会延迟安装 MCPWM 故障的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_operator` 移除。 + + +.. _mcpwm-generator-force-actions: + +生成器强制操作 +^^^^^^^^^^^^^^^^^^^^^^^ + +调用 :cpp:func:`mcpwm_generator_set_force_level`,使能软件强制决定运行时的生成器输出电平。相较于通过 :cpp:func:`mcpwm_generator_set_actions_on_timer_event` 配置的其他事件操作,软件强制事件优先级最高。 + +- 设置 ``level`` 为 -1,代表禁用强制操作,生成器的输出电平重新交由事件操作控制。 +- 设置 ``hold_on`` 为 true,代表强制输出电平将保持不变,直到设置 ``level`` 为 -1 来移除该电平。 +- 设置 ``hole_on`` 为 false,代表强制输出电平仅在短时间有效,随后发生的任何事件都可以改变该电平。 + + +.. _mcpwm-synchronization: + +同步模块 +^^^^^^^^^^^^^^^ + +MCPWM 定时器接收到同步信号后,定时器将强制进入一个预定义的 **相位**,该相位由计数值和计数方向共同决定。调用 :cpp:func:`mcpwm_timer_set_phase_on_sync`,设置同步相位。同步相位配置定义在 :cpp:type:`mcpwm_timer_sync_phase_config_t` 结构体中: + +- :cpp:member:`mcpwm_timer_sync_phase_config_t::sync_src` 设置同步信号源。创建同步源对象的相关操作,请参见 `MCPWM 同步源`_。具体来说,当此参数设置为 ``NULL`` 时,驱动器将禁用 MCPWM 定时器的同步功能。 +- :cpp:member:`mcpwm_timer_sync_phase_config_t::count_value` 设置接收同步信号后加载至计数器的值。 +- :cpp:member:`mcpwm_timer_sync_phase_config_t::direction` 设置接收同步信号后的计数方向。 + +同理, `MCPWM 捕获定时器和通道`_ 也支持同步。调用 :cpp:func:`mcpwm_capture_timer_set_phase_on_sync`,设置捕获定时器的同步相位。同步相位配置定义在 :cpp:type:`mcpwm_capture_timer_sync_phase_config_t` 结构体中: + +- :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::sync_src` 设置同步信号源。关于如何创建一个同步源对象,请参见 `MCPWM 同步源`_。具体来说,当此参数设置为 ``NULL`` 时,驱动器将禁用 MCPWM 捕获定时器的同步功能。 +- :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::count_value` 设置接收同步信号后加载至计数器的值。 +- :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::direction` 设置接收同步信号后的计数方向。需注意,不同于 MCPWM 定时器,捕获定时器只支持 :cpp:enumerator:`MCPWM_TIMER_DIRECTION_UP` 这一个计数方向。 + +使用 GPIO 同步定时器 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. blockdiag:: + :caption: GPIO Sync All MCPWM Timers + :align: center + + blockdiag { + GPIO -> Timer0, Timer1, Timer2; + } + +.. code-block:: c + + static void example_setup_sync_strategy(mcpwm_timer_handle_t timers[]) + { + mcpwm_sync_handle_t gpio_sync_source = NULL; + mcpwm_gpio_sync_src_config_t gpio_sync_config = { + .group_id = 0, // GPIO 故障应与以上定时器位于同一组中 + .gpio_num = EXAMPLE_SYNC_GPIO, + .flags.pull_down = true, + .flags.active_neg = false, // 默认情况下,一个上升沿脉冲可以触发一个同步事件 + }; + ESP_ERROR_CHECK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_source)); + + 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)); + } + } + + +.. _mcpwm-capture: + +捕获模块 +^^^^^^^^^^^^^ + +MCPWM 捕获的主要功能是记录捕获信号的脉冲边沿的有效时间。可以通过捕获得到脉宽,随后使用捕获回调函数将脉宽转换为其他物理量,如距离或速度。例如,在下图的无刷直流电机 (BLDC) 方案中,可以使用捕获子模块来确认来自霍尔传感器的转子位置。 + +.. figure:: ../../../_static/mcpwm-bldc-control.png + :align: center + :alt: 带霍尔传感器的 MCPWM 无刷直流电机 + + 带霍尔传感器的 MCPWM 无刷直流电机 + +通常,捕获定时器连接了数个捕获通道。有关资源分配的相关信息,请参见 `MCPWM 捕获定时器和通道`_。 + +注册捕获事件回调 +~~~~~~~~~~~~~~~~~~~~~~~~ + +MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须调用 :cpp:func:`mcpwm_capture_channel_register_event_callbacks`,注册一个回调函数来获得捕获的定时器计数值。回调函数原型声明在 :cpp:type:`mcpwm_capture_event_cb_t` 中,可以调用 :cpp:type:`mcpwm_capture_event_callbacks_t` 查看支持的捕获回调: + +- :cpp:member:`mcpwm_capture_event_callbacks_t::on_cap` 设置检测到有效边沿时捕获通道的回调函数。 + +回调函数会针对特定事件,提供 :cpp:type:`mcpwm_capture_event_data_t` 类型的数据,由此,可以通过 :cpp:member:`mcpwm_capture_event_data_t::cap_edge` 和 :cpp:member:`mcpwm_capture_event_data_t::cap_value` 分别得到捕获信号的边沿及该捕获的计数值。随后,调用 :cpp:func:`mcpwm_capture_timer_get_resolution`,获取捕获定时器的分辨率,以将捕获计数转换为时间戳。 + +由于上述回调函数在 ISR 中调用,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。 + +函数 :cpp:func:`mcpwm_capture_channel_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。 + +此函数会延迟安装 MCPWM 故障的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_capture_channel` 移除。 + +启用或禁用捕获通道 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +调用 :cpp:func:`mcpwm_new_capture_channel` 进行分配后,捕获通道不会自动启用。应调用 :cpp:func:`mcpwm_capture_channel_enable` 或 :cpp:func:`mcpwm_capture_channel_disable` 来启用或禁用该通道。如果在为通道注册事件回调时,由于调用了 :cpp:func:`mcpwm_capture_channel_register_event_callbacks`,致使延迟安装中断服务,则调用 :cpp:func:`mcpwm_capture_channel_enable` 启用通道时,也将启用中断服务。 + +启用或禁用捕获定时器 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +在对捕获定时器进行 IO 控制之前,需要首先调用 :cpp:func:`mcpwm_capture_timer_enable`,启用定时器。此函数将进行如下内部操作: + +* 将捕获定时器的状态从 **init** 切换到 **enable**。 +* 如果选择了一个特定时钟源(例如 APB 时钟),则获取一个对应的电源管理锁。更多信息请参见 :ref:`mcpwm-power-management`。 + +反之,调用 :cpp:func:`mcpwm_capture_timer_disable` 将使定时器驱动程序切换回 **init** 状态,并释放电源管理锁。 + +启动或停止捕获定时器 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +通过基本的 IO 控制,即可启动或停止捕获定时器。调用 :cpp:func:`mcpwm_capture_timer_start` 启动捕获定时器,或调用 :cpp:func:`mcpwm_capture_timer_stop` 立即停止捕获定时器。 + +触发软件捕获事件 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +某些场景下,可能存在需要软件触发“虚假”捕获事件的需求。此时,可以调用 :cpp:func:`mcpwm_capture_channel_trigger_soft_catch` 实现。需注意,此类“虚假”捕获事件仍然会触发中断,并从而调用捕获事件回调函数。 + + +.. _mcpwm-power-management: + +电源管理 +^^^^^^^^^^^^^^^^ + +启用电源管理(即开启 :ref:`CONFIG_PM_ENABLE`)时,系统会在进入 Light-sleep 前调整 PLL 和 APB 频率。该操作有可能会改变 MCPWM 定时器的计数步长,导致计时偏差。 + +不过,驱动程序可以获取 :cpp:enumerator:`ESP_PM_APB_FREQ_MAX` 类型的电源管理锁,防止系统改变 APB 频率。每当驱动创建以 :cpp:enumerator:`MCPWM_TIMER_CLK_SRC_PLL160M` 作为时钟源的 MCPWM 定时器实例时,都会在通过 :cpp:func:`mcpwm_timer_enable` 启用定时器时获取电源管理锁。反之,调用 :cpp:func:`mcpwm_timer_disable` 时,驱动程序释放锁。 + +同理,每当驱动创建一个以 :cpp:enumerator:`MCPWM_CAPTURE_CLK_SRC_APB` 作为时钟源的 MCPWM 捕获定时器实例时,都会在通过 :cpp:func:`mcpwm_capture_timer_enable` 启用定时器时获取电源管理锁,并在调用 :cpp:func:`mcpwm_capture_timer_disable` 时释放锁。 + + +.. _mcpwm-iram-safe: + +IRAM 安全 +^^^^^^^^^^^^^ + +默认情况下,禁用 cache 时,写入/擦除 flash 等原因将导致 MCPWM 中断延迟,事件回调函数也将延迟执行。在实时应用程序中,应避免此类情况。 + +因此,可以启用 Kconfig 选项 :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE`,该选项: + +* 支持在禁用 cache 时启用所需中断 +* 支持将 ISR 使用的所有函数存放在 IRAM 中 [2]_ +* 支持将驱动程序存放在 DRAM 中(以防其意外映射到 PSRAM 中) + +启用该选项可以保证 cache 禁用时的中断运行,但会相应增加 IRAM 占用。 + +另一个 Kconfig 选项 :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` 也支持将常用的 IO 控制函数存放在 IRAM 中,以保证在禁用 cache 时可以正常使用函数。IO 控制函数如下所示: + +- :cpp:func:`mcpwm_comparator_set_compare_value` + + +.. _mcpwm-thread-safety: + +线程安全 +^^^^^^^^^^^^^ + +驱动程序会确保工厂函数(如 :cpp:func:`mcpwm_new_timer`)的线程安全,使用时,可以直接从不同的 RTOS 任务中调用此类函数,无需额外锁保护。 + +驱动程序设置了临界区,以防函数同时在任务和 ISR 中调用。因此,以下函数支持在 ISR 上下文运行: + +- :cpp:func:`mcpwm_comparator_set_compare_value` + +:ref:`mcpwm-resource-allocation-and-initialization` 中尚未提及的函数并非线程安全。在没有设置互斥锁保护的任务中,应避免调用这些函数。 + + +.. _mcpwm-kconfig-options: + +Kconfig 选项 +^^^^^^^^^^^^^^^ + +- :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE` 控制默认 ISR 处理程序能否在禁用 cache 的情况下工作。更多信息请参见 :ref:`mcpwm-iram-safe`。 +- :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` 控制 MCPWM 控制函数的存放位置(IRAM 或 flash)。更多信息请参见 :ref:`mcpwm-iram-safe`。 +- :ref:`CONFIG_MCPWM_ENABLE_DEBUG_LOG` 用于启用调试日志输出。启用此选项将增加固件的二进制文件大小。 + +应用示例 +-------------------- + +* 通过 PID 算法控制有刷直流电机速度::example:`peripherals/mcpwm/mcpwm_bdc_speed_control` +* 控制带霍尔传感器反馈的无刷直流电机::example:`peripherals/mcpwm/mcpwm_bldc_hall_control` +* 使用超声波传感器 (HC-SR04) 测量距离::example:`peripherals/mcpwm/mcpwm_capture_hc_sr04` +* 控制伺服电机角度::example:`peripherals/mcpwm/mcpwm_servo_control` +* 定时器之间的 MCPWM 同步::example:`peripherals/mcpwm/mcpwm_sync` + + +API Reference +------------- + +.. include-build-file:: inc/mcpwm_timer.inc +.. include-build-file:: inc/mcpwm_oper.inc +.. include-build-file:: inc/mcpwm_cmpr.inc +.. include-build-file:: inc/mcpwm_gen.inc +.. include-build-file:: inc/mcpwm_fault.inc +.. include-build-file:: inc/mcpwm_sync.inc +.. include-build-file:: inc/mcpwm_cap.inc +.. include-build-file:: inc/components/driver/mcpwm/include/driver/mcpwm_types.inc +.. include-build-file:: inc/components/hal/include/hal/mcpwm_types.inc + + +.. [1] + 不同的 ESP 芯片上的 MCPWM 资源数量可能存在差异(如组、定时器、比较器、操作器、生成器等)。详情请参见 [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__]。当分配了超出资源数量的 MCPWM 资源时,在检测到没有可用硬件资源后,驱动程序将返回错误。请在进行 :ref:`mcpwm-resource-allocation-and-initialization` 时务必检查返回值。 + +.. [2] + 回调函数及其调用的子函数需手动存放进 IRAM 中。 diff --git a/docs/zh_CN/libraries-and-frameworks/index.rst b/docs/zh_CN/libraries-and-frameworks/index.rst index 82ff99d46f..9147d6d9c9 100644 --- a/docs/zh_CN/libraries-and-frameworks/index.rst +++ b/docs/zh_CN/libraries-and-frameworks/index.rst @@ -1 +1,9 @@ -.. include:: ../../en/libraries-and-frameworks/index.rst +库与框架 +************************ +:link_to_translation:`en:[English]` + +.. toctree:: + :maxdepth: 1 + + cloud-frameworks + libs-frameworks