Merge branch 'feature/mcpwm_timer_change_freq_v5.1' into 'release/v5.1'

feat(mcpwm): support update timer period dynamically (v5.1)

See merge request espressif/esp-idf!26624
This commit is contained in:
morris 2023-11-13 17:55:52 +08:00
commit efafacae40
9 changed files with 90 additions and 33 deletions

View File

@ -20,3 +20,4 @@ entries:
dac_continuous: dac_continuous_write_asynchronously (noflash)
if MCPWM_CTRL_FUNC_IN_IRAM = y:
mcpwm_cmpr: mcpwm_comparator_set_compare_value (noflash)
mcpwm_timer: mcpwm_timer_set_period (noflash)

View File

@ -69,6 +69,24 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
*/
esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer);
/**
* @brief Set a new period for MCPWM timer
*
* @note If `mcpwm_timer_config_t::update_period_on_empty` and `mcpwm_timer_config_t::update_period_on_sync` are not set,
* the new period will take effect immediately.
* Otherwise, the new period will take effect when timer counts to zero or on sync event.
* @note You may need to use `mcpwm_comparator_set_compare_value` to set a new compare value for MCPWM comparator
* in order to keep the same PWM duty cycle.
*
* @param[in] timer MCPWM timer handle, allocated by `mcpwm_new_timer`
* @param[in] period_ticks New period in count ticks
* @return
* - ESP_OK: Set new period for MCPWM timer successfully
* - ESP_ERR_INVALID_ARG: Set new period for MCPWM timer failed because of invalid argument
* - ESP_FAIL: Set new period for MCPWM timer failed because of other error
*/
esp_err_t mcpwm_timer_set_period(mcpwm_timer_handle_t timer, uint32_t period_ticks);
/**
* @brief Enable MCPWM timer
*

View File

@ -95,6 +95,12 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
TAG, "invalid interrupt priority:%d", config->intr_priority);
}
// check the peak ticks that the timer can reach to
uint32_t peak_ticks = config->period_ticks;
if (config->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) {
peak_ticks /= 2; // in symmetric mode, peak_ticks = period_ticks / 2
}
ESP_GOTO_ON_FALSE(peak_ticks > 0 && peak_ticks < MCPWM_LL_MAX_COUNT_VALUE, ESP_ERR_INVALID_ARG, err, TAG, "invalid period ticks");
timer = heap_caps_calloc(1, sizeof(mcpwm_timer_t), MCPWM_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for timer");
@ -125,10 +131,6 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
// set the peak tickes that the timer can reach to
timer->count_mode = config->count_mode;
uint32_t peak_ticks = config->period_ticks;
if (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) {
peak_ticks /= 2; // in symmetric mode, peak_ticks = period_ticks / 2
}
timer->peak_ticks = peak_ticks;
mcpwm_ll_timer_set_peak(hal->dev, timer_id, peak_ticks, timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN);
// set count direction
@ -174,6 +176,22 @@ esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer)
return ESP_OK;
}
esp_err_t mcpwm_timer_set_period(mcpwm_timer_handle_t timer, uint32_t period_ticks)
{
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
mcpwm_group_t *group = timer->group;
int timer_id = timer->timer_id;
mcpwm_hal_context_t *hal = &group->hal;
uint32_t peak_ticks = period_ticks;
if (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) {
peak_ticks /= 2; // in symmetric mode, peak_ticks = period_ticks / 2
}
ESP_RETURN_ON_FALSE_ISR(peak_ticks > 0 && peak_ticks < MCPWM_LL_MAX_COUNT_VALUE, ESP_ERR_INVALID_ARG, TAG, "invalid period ticks");
mcpwm_ll_timer_set_peak(hal->dev, timer_id, peak_ticks, timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN);
timer->peak_ticks = peak_ticks;
return ESP_OK;
}
esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const mcpwm_timer_event_callbacks_t *cbs, void *user_data)
{
ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
@ -203,8 +221,8 @@ esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const
int isr_flags = MCPWM_INTR_ALLOC_FLAG;
isr_flags |= mcpwm_get_intr_priority_flag(group);
ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags,
(uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_TIMER_MASK(timer_id),
mcpwm_timer_default_isr, timer, &timer->intr), TAG, "install interrupt service for timer failed");
(uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_TIMER_MASK(timer_id),
mcpwm_timer_default_isr, timer, &timer->intr), TAG, "install interrupt service for timer failed");
}
// enable/disable interrupt events

View File

@ -177,9 +177,26 @@ TEST_CASE("mcpwm_timer_event_callbacks", "[mcpwm]")
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_STOP, pdTRUE, pdTRUE, pdMS_TO_TICKS(50));
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_STOP, bits);
printf("update timer period\r\n");
TEST_ESP_OK(mcpwm_timer_set_period(timer, 50 * 1000)); // period: 50ms, 20Hz
udata.accumulate_empty_counts = 0;
udata.accumulate_full_counts = 0;
printf("start timer\r\n");
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
printf("wait for full and empty events\r\n");
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, pdTRUE, pdTRUE, pdMS_TO_TICKS(1500));
// because the timer period changed, the previous wait time is not sufficient, so timeout
TEST_ASSERT_EQUAL(0, bits);
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, pdTRUE, pdTRUE, pdMS_TO_TICKS(1500));
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, bits);
printf("stop timer\r\n");
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
printf("disable timer\r\n");
TEST_ESP_OK(mcpwm_timer_disable(timer));
printf("delete timer\r\n");
TEST_ESP_OK(mcpwm_del_timer(timer));
vEventGroupDelete(event_group);

View File

@ -207,13 +207,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}

View File

@ -218,13 +218,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}

View File

@ -216,13 +216,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}

View File

@ -207,13 +207,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}

View File

@ -15,16 +15,16 @@ 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. You 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 triggers the capture timer to store the time-base count value and then notify you by an interrupt. Using this feature, you can measure a pulse width precisely. What is more, the capture timer can also be synchronized by the MCPWM Sync submodule.
Functional Overview
-------------------
@ -147,7 +147,7 @@ To allocate a GPIO sync source, you can call :cpp:func:`mcpwm_new_gpio_sync_src`
- :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::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 falling 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.
@ -188,7 +188,7 @@ Next, to allocate a capture channel, you can call :cpp:func:`mcpwm_new_capture_c
- :cpp:member:`mcpwm_capture_channel_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority.
- :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::pos_edge` and :cpp:member:`mcpwm_capture_channel_config_t::neg_edge` set whether to capture on the positive and/or falling 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.
@ -212,8 +212,13 @@ MCPWM allows configuring interrupts separately for timer, operator, comparator,
Timer Operations and Events
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Register Event Callbacks
~~~~~~~~~~~~~~~~~~~~~~~~
Update Period
~~~~~~~~~~~~~
The timer period is initialized by the :cpp:member:`mcpwm_timer_config_t::period_ticks` parameter in :cpp:type:`mcpwm_timer_config_t`. You can update the period at runtime by calling :cpp:func:`mcpwm_timer_set_period` function. The new period will take effect based on how you set the :cpp:member:`mcpwm_timer_config_t::update_period_on_empty` and :cpp:member:`mcpwm_timer_config_t::update_period_on_sync` parameters in :cpp:type:`mcpwm_timer_config_t`. If none of them are set, the timer period will take effect immediately.
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`:
@ -306,7 +311,7 @@ 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
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:
@ -435,7 +440,7 @@ 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>`__.
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 new 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``.
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 new generator (``out_generator``) after applying the dead time. Please note, if the ``out_generator`` and ``in_generator`` are the same, it means you 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 you are 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:
@ -697,7 +702,7 @@ 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 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. Because 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -811,7 +816,7 @@ Sync Timers by GPIO
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, you can use the capture submodule to sense the rotor position from the Hall sensor.
.. figure:: ../../../_static/mcpwm-bldc-control.png
:align: center
@ -887,6 +892,7 @@ This will allow the interrupt to run while the cache is disabled but will come a
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:
- :cpp:func:`mcpwm_comparator_set_compare_value`
- :cpp:func:`mcpwm_timer_set_period`
Thread Safety
^^^^^^^^^^^^^
@ -896,6 +902,7 @@ The factory functions like :cpp:func:`mcpwm_new_timer` are guaranteed to be thre
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.
- :cpp:func:`mcpwm_comparator_set_compare_value`
- :cpp:func:`mcpwm_timer_set_period`
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.