mcpwm.rst 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. 电机控制脉宽调制器 (MCPWM)
  2. ===========================================
  3. :link_to_translation:`en:[English]`
  4. MCPWM 外设是一个多功能 PWM 生成器,集成多个子模块,在电力电子应用(如电机控制、数字电源等)中至关重要。MCPWM 外设通常适用于以下场景:
  5. - 数字电机控制,如有刷/无刷直流电机、RC 伺服电机
  6. - 基于开关模式的数字电源转换
  7. - 功率数模转换器 (Power DAC),其中占空比等于 DAC 的模拟值
  8. - 计算外部脉宽,并将其转换为其他模拟值,如速度、距离
  9. - 为磁场定向控制 (FOC) 生成空间矢量调制 (SVPWM) 信号
  10. 外设的主要子模块如下图所示:
  11. .. blockdiag:: /../_static/diagrams/mcpwm/mcpwm_overview.diag
  12. :caption: MCPWM 概述
  13. :align: center
  14. - **MCPWM 定时器模块**:最终输出 PWM 信号的时间基准。它也决定了其他子模块的事件时序。
  15. - **MCPWM 操作器模块**:生成 PWM 波形的关键模块。它由其他子模块组成,如比较器、PWM 生成器、死区生成器和载波调制器。
  16. - **MCPWM 比较器模块**:输入时间基准值,并不断与配置的阈值进行比较。当定时器计数值等于任何一个阈值时,生成一个比较事件,MCPWM 生成器随即相应更新其电平。
  17. - **MCPWM 生成器模块**:根据 MCPWM 定时器、MCPWM 比较器等子模块触发的各种事件,生成一对独立或互补的 PWM 波形。
  18. - **MCPWM 故障检测模块**:通过 GPIO 交换矩阵检测外部的故障情况。检测到故障信号时,MCPWM 操作器将强制所有生成器进入预先定义的状态,从而保护系统。
  19. - **MCPWM 同步模块**:同步 MCPWM 定时器,以确保由不同的 MCPWM 生成器最终生成的 PWM 信号具有固定的相位差。可以通过 GPIO 交换矩阵和 MCPWM 定时器事件生成同步信号。
  20. - **死区生成器模块**:在此前生成的 PWM 边沿上插入额外的延迟。
  21. - **载波模块**:可通过 PWM 波形生成器和死区生成器,将一个高频载波信号调制为 PWM 波形,这是控制功率开关器件的必需功能。
  22. - **制动控制**:MCPWM 操作器支持配置检测到特定故障时生成器的制动控制方式。根据故障的严重程度,可以选择立即关闭或是逐周期调节 PWM 输出。
  23. - **MCPWM 捕获模块**:独立子模块,不依赖于上述 MCPWM 操作器工作。捕获模块包括一个专用的定时器和几个独立的通道,每个通道都与 GPIO 相连。GPIO 上的脉冲触发捕获定时器以存储时间基准值,随后通过中断进行通知。此模块有助于更加精准地测量脉宽。此外,捕获定时器也可以通过 MCPWM 同步子模块进行同步。
  24. 功能概述
  25. -------------------
  26. 下文将分节概述 MCPWM 的功能:
  27. .. list::
  28. - :ref:`mcpwm-resource-allocation-and-initialization` - 介绍各类 MCPWM 模块的分配,如定时器、操作器、比较器、生成器等。随后介绍的 IO 设置和控制功能也将围绕这些模块进行。
  29. - :ref:`mcpwm-timer-operations-and-events` - 介绍 MCPWM 定时器支持的控制功能和事件回调。
  30. - :ref:`mcpwm-comparator-operations-and-events` - 介绍 MCPWM 比较器支持的控制功能和事件回调。
  31. - :ref:`mcpwm-generator-actions-on-events` - 介绍如何针对 MCPWM 定时器和比较器生成的特定事件,设置 MCPWM 生成器的相应执行操作。
  32. - :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - 介绍一些经典 PWM 波形的生成器配置。
  33. - :ref:`mcpwm-dead-time` - 介绍如何设置 MCPWM 生成器的死区时间。
  34. - :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - 介绍一些经典 PWM 波形的死区配置。
  35. - :ref:`mcpwm-carrier-modulation` - 介绍如何在最终输出的 PWM 波形上调制高频载波。
  36. - :ref:`mcpwm-faults-and-brake-actions` - 介绍如何为 MCPWM 操作器配置特定故障事件下的制动操作。
  37. - :ref:`mcpwm-generator-force-actions` - 介绍如何强制异步控制生成器的输出水平。
  38. - :ref:`mcpwm-synchronization` - 介绍如何同步 MCPWM 定时器,并确保生成的最终输出 PWM 信号具有固定的相位差。
  39. - :ref:`mcpwm-capture` - 介绍如何使用 MCPWM 捕获模块测量信号脉宽。
  40. :SOC_MCPWM_SUPPORT_ETM: - :ref:`mcpwm-etm-event-and-task` - MCPWM 提供了哪些事件和任务可以连接到 ETM 通道上。
  41. - :ref:`mcpwm-power-management` - 介绍不同的时钟源对功耗的影响。
  42. - :ref:`mcpwm-iram-safe` - 介绍如何协调 RMT 中断与禁用缓存。
  43. - :ref:`mcpwm-thread-safety` - 列出了由驱动程序认证为线程安全的 API。
  44. - :ref:`mcpwm-kconfig-options` - 列出了针对驱动的数个 Kconfig 支持选项。
  45. .. _mcpwm-resource-allocation-and-initialization:
  46. 资源配置及初始化
  47. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  48. 如上图所示,MCPWM 外设由数个子模块组成。本节将介绍各个子模块的资源配置方式。
  49. MCPWM 定时器
  50. ~~~~~~~~~~~~~~~
  51. 调用 :cpp:func:`mcpwm_new_timer` 函数,以配置结构体 :cpp:type:`mcpwm_timer_config_t` 为参数,分配一个 MCPWM 定时器为对象。结构体定义为:
  52. - :cpp:member:`mcpwm_timer_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的定时器彼此独立。
  53. - :cpp:member:`mcpwm_timer_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
  54. - :cpp:member:`mcpwm_timer_config_t::clk_src` 设置定时器的时钟源。
  55. - :cpp:member:`mcpwm_timer_config_t::resolution_hz` 设置定时器的预期分辨率。内部驱动将根据时钟源和分辨率设置合适的分频器。
  56. - :cpp:member:`mcpwm_timer_config_t::count_mode` 设置定时器的计数模式。
  57. - :cpp:member:`mcpwm_timer_config_t::period_ticks` 设置定时器的周期,以 Tick 为单位(通过 :cpp:member:`mcpwm_timer_config_t::resolution_hz` 设置 Tick 分辨率)。
  58. - :cpp:member:`mcpwm_timer_config_t::update_period_on_empty` 设置当定时器计数为零时是否更新周期值。
  59. - :cpp:member:`mcpwm_timer_config_t::update_period_on_sync` 设置当定时器接收同步信号时是否更新周期值。
  60. 分配成功后,:cpp:func:`mcpwm_new_timer` 将返回一个指向已分配定时器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲定时器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  61. 反之,调用 :cpp:func:`mcpwm_del_timer` 函数将释放已分配的定时器。
  62. MCPWM 操作器
  63. ~~~~~~~~~~~~~~~
  64. 调用 :cpp:func:`mcpwm_new_operator` 函数,以配置结构体 :cpp:type:`mcpwm_operator_config_t` 为参数,分配一个 MCPWM 操作器为对象。结构体定义为:
  65. - :cpp:member:`mcpwm_operator_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的操作器彼此独立。
  66. - :cpp:member:`mcpwm_operator_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
  67. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tez` 设置是否在定时器计数为零时更新生成器操作。此处及下文提到的定时器指通过 :cpp:func:`mcpwm_operator_connect_timer` 连接到操作器的定时器。
  68. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_tep` 设置当定时器计数达到峰值时是否更新生成器操作。
  69. - :cpp:member:`mcpwm_operator_config_t::update_gen_action_on_sync` 设置当定时器接收同步信号时是否更新生成器操作。
  70. - :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tez` 设置当定时器计数为零时是否更新死区时间。
  71. - :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_tep` 设置当定时器计数达到峰值时是否更新死区时间。
  72. - :cpp:member:`mcpwm_operator_config_t::update_dead_time_on_sync` 设置当定时器接收同步信号时是否更新死区时间。
  73. 分配成功后,:cpp:func:`mcpwm_new_operator` 将返回一个指向已分配操作器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲操作器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  74. 反之,调用 :cpp:func:`mcpwm_del_operator` 函数将释放已分配的操作器。
  75. MCPWM 比较器
  76. ~~~~~~~~~~~~~~~~~
  77. 调用 :cpp:func:`mcpwm_new_comparator` 函数,以一个 MCPWM 操作器句柄和配置结构体 :cpp:type:`mcpwm_comparator_config_t` 为参数,分配一个 MCPWM 比较器为对象。操作器句柄由 :cpp:func:`mcpwm_new_operator` 生成,结构体定义为:
  78. - :cpp:member:`mcpwm_comparator_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
  79. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tez` 设置当定时器计数为零时是否更新比较阈值。
  80. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_tep` 设置当定时器计数达到峰值时是否更新比较阈值。
  81. - :cpp:member:`mcpwm_comparator_config_t::update_cmp_on_sync` 设置当定时器接收同步信号时是否更新比较阈值。
  82. 分配成功后,:cpp:func:`mcpwm_new_comparator` 将返回一个指向已分配比较器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 操作器中没有空闲比较器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  83. 反之,调用 :cpp:func:`mcpwm_del_comparator` 函数将释放已分配的比较器。
  84. .. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
  85. MCPWM 中还有另外一种比较器 —— “事件比较器”,它不能直接控制 PWM 的输出,只能用来产生 EMT 子系统中使用到的事件。事件比较器能够设置的阈值也是可配的。调用 :cpp:func:`mcpwm_new_event_comparator` 函数可以申请一个事件比较器,该函数返回的句柄类型和 :cpp:func:`mcpwm_new_comparator` 函数一样,但是需要的配置结构体是不同的。事件比较器的配置位于 :cpp:type:`mcpwm_event_comparator_config_t`。更多相关内容请参阅 :ref:`mcpwm-etm-event-and-task`。
  86. MCPWM 生成器
  87. ~~~~~~~~~~~~~~~~
  88. 调用 :cpp:func:`mcpwm_new_generator` 函数,以一个 MCPWM 操作器句柄和配置结构体 :cpp:type:`mcpwm_generator_config_t` 为参数,分配一个 MCPWM 生成器为对象。操作器句柄由 :cpp:func:`mcpwm_new_operator` 生成,结构体定义为:
  89. - :cpp:member:`mcpwm_generator_config_t::gen_gpio_num` 设置生成器使用的 GPIO 编号。
  90. - :cpp:member:`mcpwm_generator_config_t::invert_pwm` 设置是否反相 PWM 信号。
  91. - :cpp:member:`mcpwm_generator_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。
  92. - :cpp:member:`mcpwm_generator_config_t::io_od_mode` 设置是否启用漏极开路输出。
  93. - :cpp:member:`mcpwm_generator_config_t::pull_up` 和 :cpp:member:`mcpwm_generator_config_t::pull_down` 用来设置是否启用内部上下拉电阻。
  94. 分配成功后,:cpp:func:`mcpwm_new_generator` 将返回一个指向已分配生成器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 操作器中没有空闲生成器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  95. 反之,调用 :cpp:func:`mcpwm_del_generator` 函数将释放已分配的生成器。
  96. MCPWM 故障
  97. ~~~~~~~~~~~~
  98. MCPWM 故障分为两种类型:来自 GPIO 的故障信号和软件故障。
  99. 调用 :cpp:func:`mcpwm_new_gpio_fault` 函数,以配置结构体 :cpp:type:`mcpwm_gpio_fault_config_t` 为参数,分配一个 GPIO 故障为对象。结构体定义为:
  100. - :cpp:member:`mcpwm_gpio_fault_config_t::group_id` 设置 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的 GPIO 故障彼此独立,也就是说,1 组的操作器无法检测到 0 组的 GPIO 故障。
  101. - :cpp:member:`mcpwm_gpio_fault_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
  102. - :cpp:member:`mcpwm_gpio_fault_config_t::gpio_num` 设置故障所使用的 GPIO 编号。
  103. - :cpp:member:`mcpwm_gpio_fault_config_t::active_level` 设置故障信号的有效电平。
  104. - :cpp:member:`mcpwm_gpio_fault_config_t::pull_up` 和 :cpp:member:`mcpwm_gpio_fault_config_t::pull_down` 设置是否在内部拉高和/或拉低 GPIO。
  105. - :cpp:member:`mcpwm_gpio_fault_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。
  106. 分配成功后,:cpp:func:`mcpwm_new_gpio_fault` 将返回一个指向已分配故障的指针。否则,函数将返回错误代码。具体来说,当指定 MCPWM 组中没有空闲 GPIO 故障时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  107. 调用函数 :cpp:func:`mcpwm_soft_fault_activate` 使一个软件故障对象触发故障,无需等待来自 GPIO 的真实故障信号。调用 :cpp:func:`mcpwm_new_soft_fault` 函数,以配置结构体 :cpp:type:`mcpwm_soft_fault_config_t` 为参数,分配一个软件故障为对象。该结构体暂时保留,供后续使用。
  108. 分配成功后,:cpp:func:`mcpwm_new_soft_fault` 将返回一个指向已分配故障的指针。否则,函数将返回错误代码。具体来说,当内存不足以支持该故障对象时,将返回 :c:macro:`ESP_ERR_NO_MEM` 错误。虽然软件故障和 GPIO 故障是不同类型的故障,但返回的故障句柄为同一类型。
  109. 反之,调用 :cpp:func:`mcpwm_del_fault` 函数将释放已分配的故障。此函数同时适用于软件故障和 GPIO 故障。
  110. MCPWM 同步源
  111. ~~~~~~~~~~~~~~~~~~
  112. 同步源用于同步 MCPWM 定时器和 MCPWM 捕获定时器,分为三种类型:来自 GPIO 的同步源、软件生成的同步源和 MCPWM 定时器事件生成的同步源。
  113. 调用 :cpp:func:`mcpwm_new_gpio_sync_src` 函数,以配置结构体 :cpp:type:`mcpwm_gpio_sync_src_config_t` 为参数,分配一个 GPIO 同步源。结构体定义为:
  114. - :cpp:member:`mcpwm_gpio_sync_src_config_t::group_id` 指定 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。需注意,位于不同组的 GPIO 同步源彼此独立,也就是说,1 组的定时器无法检测到 0 组的 GPIO 同步源。
  115. - :cpp:member:`mcpwm_gpio_sync_src_config_t::gpio_num` 设置同步源使用的 GPIO 编号。
  116. - :cpp:member:`mcpwm_gpio_sync_src_config_t::active_neg` 设置同步信号在下降沿是否有效。
  117. - :cpp:member:`mcpwm_gpio_sync_src_config_t::pull_up` 和 :cpp:member:`mcpwm_gpio_sync_src_config_t::pull_down` 设置是否在内部拉高和/或拉低 GPIO。
  118. - :cpp:member:`mcpwm_gpio_sync_src_config_t::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。
  119. 分配成功后,:cpp:func:`mcpwm_new_gpio_sync_src` 将返回一个指向已分配同步源的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲 GPIO 时钟源时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  120. 调用 :cpp:func:`mcpwm_new_timer_sync_src` 函数,以配置结构体 :cpp:type:`mcpwm_timer_sync_src_config_t` 为参数,分配一个定时器事件同步源。结构体定义为:
  121. - :cpp:member:`mcpwm_timer_sync_src_config_t::timer_event` 指定产生同步信号的定时器事件。
  122. - :cpp:member:`mcpwm_timer_sync_src_config_t::propagate_input_sync` 是否广播输入同步信号(即将输入同步信号传输到其同步输出)。
  123. 分配成功后,:cpp:func:`mcpwm_new_timer_sync_src` 将返回一个指向已分配同步源的指针。否则,函数将返回错误代码。具体来说,若是分配的同步源此前已分配给了同一个定时器,将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。
  124. 也可以调用 :cpp:func:`mcpwm_new_soft_sync_src` 函数,以配置结构体 :cpp:type:`mcpwm_soft_sync_config_t` 为参数,分配一个软件同步源。该结构体暂时保留,供后续使用。
  125. 分配成功后,:cpp:func:`mcpwm_new_soft_sync_src` 将返回一个指向已分配同步源的指针。否则,函数将返回错误代码。具体来说,当内存不足以支持分配的同步源时,将返回 :c:macro:`ESP_ERR_NO_MEM` 错误。需注意,为确保软件同步源能够正常工作,应预先调用 :cpp:func:`mcpwm_soft_sync_activate`。
  126. 相反,调用 :cpp:func:`mcpwm_del_sync_src` 函数将释放分配的同步源对象。此函数适用于所有类型的同步源。
  127. MCPWM 捕获定时器和通道
  128. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  129. MCPWM 组有一个专用定时器,用于捕获特定事件发生时的时间戳。捕获定时器连接了数个独立通道,每个通道都分配了各自的 GPIO。
  130. 调用 :cpp:func:`mcpwm_new_capture_timer` 函数,以配置结构体 :cpp:type:`mcpwm_capture_timer_config_t` 为参数,分配一个捕获定时器。结构体定义为:
  131. - :cpp:member:`mcpwm_capture_timer_config_t::group_id` 设置 MCPWM 组 ID,范围为 [0, :c:macro:`SOC_MCPWM_GROUPS` - 1]。
  132. - :cpp:member:`mcpwm_capture_timer_config_t::clk_src` 设置捕获定时器的时钟源。
  133. - :cpp:member:`mcpwm_capture_timer_config_t::resolution_hz` 设置捕获定时器的预期分辨率。内部驱动将根据时钟源和分辨率设置合适的分频器。设置为 ``0`` 时,驱动会自己选取一个适当的分辨率,后续你可以通过 :cpp:func:`mcpwm_capture_timer_get_resolution` 查看当前定时器的分辨率。
  134. .. only:: not SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
  135. .. note::
  136. 在 {IDF_TARGET_NAME} 中,:cpp:member:`mcpwm_capture_timer_config_t::resolution_hz` 参数无效,捕获定时器的分辨率始终等于 :cpp:enumerator:`MCPWM_CAPTURE_CLK_SRC_APB`。
  137. 分配成功后,:cpp:func:`mcpwm_new_capture_timer` 将返回一个指向已分配捕获定时器的指针。否则,函数将返回错误代码。具体来说,当 MCPWM 组中没有空闲捕获定时器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  138. 接下来,可以调用 :cpp:func:`mcpwm_new_capture_channel` 函数,以一个捕获定时器句柄和配置结构体 :cpp:type:`mcpwm_capture_channel_config_t` 为参数,分配一个捕获通道。结构体定义为:
  139. - :cpp:member:`mcpwm_capture_channel_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
  140. - :cpp:member:`mcpwm_capture_channel_config_t::gpio_num` 设置捕获通道使用的 GPIO 编号。
  141. - :cpp:member:`mcpwm_capture_channel_config_t::prescale` 设置输入信号的预分频器。
  142. - :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::pos_edge` 和 :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::neg_edge` 设置是否在输入信号的上升沿和/或下降沿捕获时间戳。
  143. - :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::pull_up` 和 :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::pull_down` 设置是否在内部拉高和/或拉低 GPIO。
  144. - :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::invert_cap_signal` 设置是否取反捕获信号。
  145. - :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::io_loop_back` 设置是否启用回环模式。该模式仅用于调试,使用 GPIO 交换矩阵外设同时启用 GPIO 输入和输出。
  146. - :cpp:member:`mcpwm_capture_channel_config_t::extra_flags::keep_io_conf_at_exit` 设置是否在删除通道时保留 GPIO 的相关配置。
  147. 分配成功后,:cpp:func:`mcpwm_new_capture_channel` 将返回一个指向已分配捕获通道的指针。否则,函数将返回错误代码。具体来说,当捕获定时器中没有空闲捕获通道时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。
  148. 反之,调用 :cpp:func:`mcpwm_del_capture_channel` 和 :cpp:func:`mcpwm_del_capture_timer` 将释放已分配的捕获通道和定时器。
  149. MCPWM 中断优先级
  150. ~~~~~~~~~~~~~~~~~~~~~~~~
  151. MCPWM 允许为 定时器、操作器、比较器、故障以及捕获事件分别配置中断,中断优先级由各自的 ``config_t::intr_priority`` 决定。且同一个 MCPWM 组中的事件共享同一个中断源。注册多个中断事件时,中断优先级需要保持一致。
  152. .. note::
  153. MCPWM 组注册多个中断事件时,驱动将以第一个事件的中断优先级作为 MCPWM 组的中断优先级。
  154. .. _mcpwm-timer-operations-and-events:
  155. 定时器操作和事件
  156. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  157. 更新定时器周期
  158. ~~~~~~~~~~~~~~
  159. 定时器周期在创建定时器时就已经通过 :cpp:member:`mcpwm_timer_config_t::period_ticks` 被初始化过了。你还可以在运行期间,调用 :cpp:func:`mcpwm_timer_set_period` 函数来更新定时周期。新周期的生效时机由 :cpp:member:`mcpwm_timer_config_t::update_period_on_empty` 和 :cpp:member:`mcpwm_timer_config_t::update_period_on_sync` 共同决定。如果他们两个参数都是 ``false``, 那么新的定时周期会立即生效。
  160. 注册定时器事件回调
  161. ~~~~~~~~~~~~~~~~~~~~~~~~
  162. MCPWM 定时器运行时会生成不同的事件。若有函数需在特定事件发生时调用,则应预先调用 :cpp:func:`mcpwm_timer_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中定时器回调函数原型声明为 :cpp:type:`mcpwm_timer_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_timer_event_callbacks_t` 中:
  163. - :cpp:member:`mcpwm_timer_event_callbacks_t::on_full` 设置定时器计数达到峰值时的回调函数。
  164. - :cpp:member:`mcpwm_timer_event_callbacks_t::on_empty` 设置定时器计数为零时的回调函数。
  165. - :cpp:member:`mcpwm_timer_event_callbacks_t::on_stop` 设置定时器停止时的回调函数。
  166. 由于上述回调函数是在 ISR 中调用的,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。
  167. 函数 :cpp:func:`mcpwm_timer_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。
  168. 此函数会在不启用 MCPWM 定时器的情况下延迟安装其中断服务。因此,需在调用 :cpp:func:`mcpwm_timer_enable` 函数前调用该函数,否则将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。更多信息请参见 `启用和禁用定时器`_。
  169. 启用和禁用定时器
  170. ~~~~~~~~~~~~~~~~~~~~~~~~
  171. 在对定时器进行 IO 控制前,需要预先调用 :cpp:func:`mcpwm_timer_enable` 函数启用定时器。这个函数将:
  172. * 将定时器的状态从 **init** 切换到 **enable**。
  173. * 若中断服务此前已通过 :cpp:func:`mcpwm_timer_register_event_callbacks` 函数延迟安装,则启用中断服务。
  174. * 若选择了特定时钟源(例如 PLL_160M 时钟),则获取相应的电源管理锁。更多信息请参见 :ref:`mcpwm-power-management`。
  175. 反之,调用 :cpp:func:`mcpwm_timer_disable` 会将定时器切换回 **init** 状态、禁用中断服务并释放电源管理锁。
  176. 启动和停止定时器
  177. ~~~~~~~~~~~~~~~~~~~~
  178. 通过基本的 IO 控制,即可启动和停止定时器。使用不同的 :cpp:type:`mcpwm_timer_start_stop_cmd_t` 命令调用 :cpp:func:`mcpwm_timer_start_stop` 便可立即启动定时器,或在发生特定事件时停止定时器。此外,还可以通过配置,让定时器仅计数一轮。也就是说,在计数达到峰值或零后,定时器自行停止。
  179. 连接定时器和操作器
  180. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  181. 调用 :cpp:func:`mcpwm_operator_connect_timer` 函数,连接分配的 MCPWM 定时器和 MCPWM 操作器。连接后,操作器即可将定时器作为时基,生成所需的 PWM 波形。需注意,MCPWM 定时器和操作器必须位于同一个组中。否则,将返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。
  182. .. _mcpwm-comparator-operations-and-events:
  183. 比较器操作和事件
  184. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  185. 注册比较器事件回调
  186. ~~~~~~~~~~~~~~~~~~~~~~~~
  187. MCPWM 比较器可以在定时器计数器等于比较值时发送通知。若有函数需在比较事件发生时调用,则应预先调用 :cpp:func:`mcpwm_comparator_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中比较器回调函数原型声明为 :cpp:type:`mcpwm_compare_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_comparator_event_callbacks_t` 中:
  188. - :cpp:member:`mcpwm_comparator_event_callbacks_t::on_reach` 设置当定时器计数器等于比较值时的比较器回调函数。
  189. 回调函数会提供类型为 :cpp:type:`mcpwm_compare_event_data_t` 的事件特定数据。由于上述回调函数是在 ISR 中调用的,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。
  190. 函数 :cpp:func:`mcpwm_comparator_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。
  191. 此函数会延迟安装 MCPWM 比较器的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_comparator` 移除。
  192. .. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
  193. .. note::
  194. 对于事件比较器,你无法通过该函数来注册回调函数,因为事件比较器触发产生任何中断事件。
  195. 设置比较值
  196. ~~~~~~~~~~~~~~~~~
  197. 运行 MCPWM 比较器时,可以调用 :cpp:func:`mcpwm_comparator_set_compare_value` 设置比较值。需注意以下几点:
  198. - 重新设置的比较值可能不会立即生效。比较值的更新时间通过 :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` 配置。
  199. - 请确保已经预先调用 :cpp:func:`mcpwm_operator_connect_timer` 将操作器连接至 MCPWM 定时器。否则,将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。
  200. - 比较值不应超过定时器的计数峰值。否则,将无法触发比较事件。
  201. .. _mcpwm-generator-actions-on-events:
  202. 生成器对事件执行的操作
  203. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  204. 设置生成器对定时器事件执行的操作
  205. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  206. 调用 :cpp:func:`mcpwm_generator_set_actions_on_timer_event` 并辅以若干操作配置,可以针对不同的定时器事件,为生成器设置不同的操作。操作配置定义在 :cpp:type:`mcpwm_gen_timer_event_action_t` 中:
  207. - :cpp:member:`mcpwm_gen_timer_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。
  208. - :cpp:member:`mcpwm_gen_timer_event_action_t::event` 指定定时器事件,可以调用 :cpp:type:`mcpwm_timer_event_t` 查看支持的定时器事件。
  209. - :cpp:member:`mcpwm_gen_timer_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。
  210. 可借助辅助宏 :c:macro:`MCPWM_GEN_TIMER_EVENT_ACTION` 构建定时器事件操作条目。
  211. 需注意,:cpp:func:`mcpwm_generator_set_actions_on_timer_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_TIMER_EVENT_ACTION_END` 结束。
  212. 也可以调用 :cpp:func:`mcpwm_generator_set_action_on_timer_event` 逐一设置定时器操作,无需涉及变量参数。
  213. 设置生成器对比较器事件执行的操作
  214. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  215. 调用 :cpp:func:`mcpwm_generator_set_actions_on_compare_event` 并辅以若干操作配置,可以针对不同的比较器事件,为生成器设置不同的操作。操作配置定义在 :cpp:type:`mcpwm_gen_compare_event_action_t` 中:
  216. - :cpp:member:`mcpwm_gen_compare_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。
  217. - :cpp:member:`mcpwm_gen_compare_event_action_t::comparator` 指定比较器句柄。有关分配比较器的方法,请参见 `MCPWM 比较器`_。
  218. - :cpp:member:`mcpwm_gen_compare_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。
  219. 可借助辅助宏 :c:macro:`MCPWM_GEN_COMPARE_EVENT_ACTION` 构建比较事件操作条目。
  220. 需注意,:cpp:func:`mcpwm_generator_set_actions_on_compare_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_COMPARE_EVENT_ACTION_END` 结束。
  221. 也可以调用 :cpp:func:`mcpwm_generator_set_action_on_compare_event` 逐一设置比较器操作,无需涉及变量参数。
  222. 设置生成器对故障事件执行的操作
  223. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  224. 调用 :cpp:func:`mcpwm_generator_set_action_on_fault_event` 并辅以操作配置,可以针对故障事件,为生成器设置操作。操作配置定义在 :cpp:type:`mcpwm_gen_fault_event_action_t` 中:
  225. - :cpp:member:`mcpwm_gen_fault_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。
  226. - :cpp:member:`mcpwm_gen_fault_event_action_t::fault` 指定用于触发器的故障。有关分配故障的方法,请参见 `MCPWM 故障`_。
  227. - :cpp:member:`mcpwm_gen_fault_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。
  228. 当生成器所属的操作器中没有空闲触发器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  229. 触发器支持的故障仅为 GPIO 故障,当传入故障不为 GPIO 故障时,将返回 :c:macro:`ESP_ERR_NOT_SUPPORTED` 错误。
  230. 可借助辅助宏 :c:macro:`MCPWM_GEN_FAULT_EVENT_ACTION` 构建触发事件操作条目。
  231. 需注意,故障事件没有类似 :cpp:func:`mcpwm_generator_set_actions_on_fault_event` 这样的可变参数函数。
  232. 设置生成器对同步事件执行的操作
  233. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  234. 调用 :cpp:func:`mcpwm_generator_set_action_on_sync_event` 并辅以操作配置,可以针对同步事件,为生成器设置操作。操作配置定义在 :cpp:type:`mcpwm_gen_sync_event_action_t` 中:
  235. - :cpp:member:`mcpwm_gen_sync_event_action_t::direction` 指定定时器计数方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。
  236. - :cpp:member:`mcpwm_gen_sync_event_action_t::sync` 指定用于触发器的同步源。有关分配同步源的方法,请参见 `MCPWM 同步源`_。
  237. - :cpp:member:`mcpwm_gen_sync_event_action_t::action` 指定随即进行的生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。
  238. 当生成器所属的操作器中没有空闲触发器时,将返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。[1]_
  239. 无论同步为何种类型,触发器仅支持一种同步操作,如果多次设置同步操作,将返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。
  240. 可借助辅助宏 :c:macro:`MCPWM_GEN_SYNC_EVENT_ACTION` 构建触发事件操作条目。
  241. 需注意,同步事件没有类似 :cpp:func:`mcpwm_generator_set_actions_on_sync_event` 这样的可变参数函数。
  242. .. _mcpwm-classical-pwm-waveforms-and-generator-configurations:
  243. 经典 PWM 波形的生成器配置
  244. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  245. 本节提供了一些生成器支持生成的经典 PWM 波形,同时提供用于生成这些波形的代码片段。总的来说:
  246. - 生成波形为 **对称波形** 还是 **不对称波形** 取决于 MCPWM 定时器的计数模式。
  247. - 波形对的 **激活电平** 取决于占空比较小的 PWM 波形的电平。
  248. - PWM 波形的周期取决于定时器的周期和计数模式。
  249. - PWM 波形的占空比取决于生成器的各种操作配置组合。
  250. 单边不对称波形 - 高电平
  251. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  252. .. wavedrom:: /../_static/diagrams/mcpwm/single_edge_asym_active_high.json
  253. .. code:: c
  254. 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)
  255. {
  256. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  257. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  258. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  259. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  260. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb,
  261. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  262. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb,
  263. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW)));
  264. }
  265. 单边不对称波形 - 低电平
  266. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  267. .. wavedrom:: /../_static/diagrams/mcpwm/single_edge_asym_active_low.json
  268. .. code:: c
  269. 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)
  270. {
  271. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  272. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW)));
  273. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  274. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH)));
  275. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb,
  276. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW)));
  277. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb,
  278. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH)));
  279. }
  280. 脉冲位置不对称波形
  281. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  282. .. wavedrom:: /../_static/diagrams/mcpwm/pulse_placement_asym.json
  283. .. code:: c
  284. 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)
  285. {
  286. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena,
  287. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
  288. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
  289. MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
  290. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(genb,
  291. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_TOGGLE),
  292. MCPWM_GEN_TIMER_EVENT_ACTION_END()));
  293. }
  294. 双沿不对称波形 - 低电平有效
  295. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  296. .. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_asym_active_low.json
  297. .. code:: c
  298. 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)
  299. {
  300. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena,
  301. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
  302. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_LOW),
  303. MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
  304. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(genb,
  305. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
  306. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH),
  307. MCPWM_GEN_TIMER_EVENT_ACTION_END()));
  308. }
  309. 双沿对称波形 - 低电平有效
  310. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  311. .. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_sym_active_low.json
  312. .. code:: c
  313. 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)
  314. {
  315. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena,
  316. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
  317. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW),
  318. MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
  319. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(genb,
  320. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH),
  321. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_LOW),
  322. MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
  323. }
  324. 双沿对称波形 - 互补
  325. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  326. .. wavedrom:: /../_static/diagrams/mcpwm/dual_edge_sym_complementary.json
  327. .. code:: c
  328. 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)
  329. {
  330. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(gena,
  331. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
  332. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW),
  333. MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
  334. ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(genb,
  335. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
  336. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_HIGH),
  337. MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
  338. }
  339. .. _mcpwm-dead-time:
  340. 死区
  341. ^^^^^^^^^
  342. 在电力电子学中,常常会用到整流器和逆变器,这就涉及到了整流桥和逆变桥的应用。每个桥臂配有两个功率电子器件,例如 MOSFET、IGBT 等。同一桥臂上的两个 MOSFET 不能同时导通,否则会造成短路。实际应用中,在 PWM 波形显示 MOSFET 开关已关闭后,仍需要一段时间窗口才能完全关闭 MOSFET。因此,需要设置 :ref:`mcpwm-generator-actions-on-events`,在已生成的 PWM 波形上添加额外延迟。
  343. 死区驱动器的工作方式与 **装饰器** 类似。在 :cpp:func:`mcpwm_generator_set_dead_time` 函数的参数中,驱动接收主要生成器句柄 (``in_generator``),并在应用死区后返回一个新的生成器 (``out_generator``)。需注意,如果 ``out_generator`` 和 ``in_generator`` 相同,这表示 PWM 波形中的时间延迟是以“就地”的方式添加的。反之,如果 ``out_generator`` 和 ``in_generator`` 不同,则代表在原 ``in_generator`` 的基础上派生出了一个新的 PWM 波形。
  344. 结构体 :cpp:type:`mcpwm_dead_time_config_t` 中列出了死区相关的具体配置:
  345. - :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` 连接操作器的定时器相同。
  346. - :cpp:member:`mcpwm_dead_time_config_t::invert_output` 设置是否在应用死区后取反信号,以控制延迟边沿的极性。
  347. .. warning::
  348. 由于硬件限制,同一种 delay 模块(``posedge delay`` 或者 ``negedge delay``)不能同时被应用在不同的 MCPWM 生成器中。例如,以下配置是无效的:
  349. .. code:: c
  350. mcpwm_dead_time_config_t dt_config = {
  351. .posedge_delay_ticks = 10,
  352. };
  353. // 给 generator A 叠加上升沿 delay
  354. mcpwm_generator_set_dead_time(mcpwm_gen_a, mcpwm_gen_a, &dt_config);
  355. // NOTE: 下面的操作是无效的,不能将同一种 delay 应用于不同的 generator 上
  356. mcpwm_generator_set_dead_time(mcpwm_gen_b, mcpwm_gen_b, &dt_config);
  357. 然而,你可以为生成器 A 设置 ``posedge delay``,为生成器 B 设置 ``negedge delay``。另外,也可以为生成器 A 同时设置 ``posedge delay`` 和 ``negedge delay``,而让生成器 B 绕过死区模块。
  358. .. note::
  359. 也可以通过设置 :ref:`mcpwm-generator-actions-on-events` 来生成所需的死区,通过不同的比较器来控制边沿位置。但是,如果需要使用经典的基于边沿延迟并附带极性控制的死区,则应使用死区子模块。
  360. .. _mcpwm-classical-pwm-waveforms-and-dead-time-configurations:
  361. 经典 PWM 波形的死区配置
  362. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  363. 本节提供了一些死区子模块支持生成的经典 PWM 波形,同时在图片下方提供用于生成这些波形的代码片段。
  364. 高电平有效互补
  365. ~~~~~~~~~~~~~~~~~~~~~~~~~
  366. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_high_complementary.json
  367. .. code:: c
  368. 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)
  369. {
  370. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  371. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  372. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  373. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  374. }
  375. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  376. {
  377. mcpwm_dead_time_config_t dead_time_config = {
  378. .posedge_delay_ticks = 50,
  379. .negedge_delay_ticks = 0
  380. };
  381. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  382. dead_time_config.posedge_delay_ticks = 0;
  383. dead_time_config.negedge_delay_ticks = 100;
  384. dead_time_config.flags.invert_output = true;
  385. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
  386. }
  387. 低电平有效互补
  388. ~~~~~~~~~~~~~~~~~~~~~~~~
  389. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_low_complementary.json
  390. .. code:: c
  391. 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)
  392. {
  393. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  394. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  395. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  396. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  397. }
  398. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  399. {
  400. mcpwm_dead_time_config_t dead_time_config = {
  401. .posedge_delay_ticks = 50,
  402. .negedge_delay_ticks = 0,
  403. .flags.invert_output = true
  404. };
  405. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  406. dead_time_config.posedge_delay_ticks = 0;
  407. dead_time_config.negedge_delay_ticks = 100;
  408. dead_time_config.flags.invert_output = false;
  409. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
  410. }
  411. 高电平有效
  412. ~~~~~~~~~~~
  413. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_high.json
  414. .. code:: c
  415. 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)
  416. {
  417. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  418. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  419. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  420. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  421. }
  422. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  423. {
  424. mcpwm_dead_time_config_t dead_time_config = {
  425. .posedge_delay_ticks = 50,
  426. .negedge_delay_ticks = 0,
  427. };
  428. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  429. dead_time_config.posedge_delay_ticks = 0;
  430. dead_time_config.negedge_delay_ticks = 100;
  431. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
  432. }
  433. 低电平有效
  434. ~~~~~~~~~~
  435. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_active_low.json
  436. .. code:: c
  437. 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)
  438. {
  439. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  440. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  441. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  442. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  443. }
  444. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  445. {
  446. mcpwm_dead_time_config_t dead_time_config = {
  447. .posedge_delay_ticks = 50,
  448. .negedge_delay_ticks = 0,
  449. .flags.invert_output = true
  450. };
  451. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  452. dead_time_config.posedge_delay_ticks = 0;
  453. dead_time_config.negedge_delay_ticks = 100;
  454. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
  455. }
  456. PWMA 上升沿延迟,绕过 PWMB 死区
  457. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  458. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_reda_bypassb.json
  459. .. code:: c
  460. 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)
  461. {
  462. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  463. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  464. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  465. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  466. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb,
  467. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  468. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb,
  469. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW)));
  470. }
  471. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  472. {
  473. mcpwm_dead_time_config_t dead_time_config = {
  474. .posedge_delay_ticks = 50,
  475. .negedge_delay_ticks = 0,
  476. };
  477. // apply deadtime to generator_a
  478. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  479. // bypass deadtime module for generator_b
  480. dead_time_config.posedge_delay_ticks = 0;
  481. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
  482. }
  483. PWMB 下降沿延迟,绕过 PWMA 死区
  484. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  485. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_fedb_bypassa.json
  486. .. code:: c
  487. 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)
  488. {
  489. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  490. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  491. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  492. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  493. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb,
  494. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  495. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb,
  496. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW)));
  497. }
  498. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  499. {
  500. mcpwm_dead_time_config_t dead_time_config = {
  501. .posedge_delay_ticks = 0,
  502. .negedge_delay_ticks = 0,
  503. };
  504. // generator_a bypass the deadtime module (no delay)
  505. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  506. // apply dead time to generator_b
  507. dead_time_config.negedge_delay_ticks = 50;
  508. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
  509. }
  510. PWMB 上升下降沿延迟,绕过 PWMA 死区
  511. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  512. .. wavedrom:: /../_static/diagrams/mcpwm/deadtime_redb_fedb_bypassa.json
  513. .. code:: c
  514. 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)
  515. {
  516. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gena,
  517. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  518. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gena,
  519. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW)));
  520. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(genb,
  521. MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
  522. ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(genb,
  523. MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW)));
  524. }
  525. static void dead_time_config(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
  526. {
  527. mcpwm_dead_time_config_t dead_time_config = {
  528. .posedge_delay_ticks = 0,
  529. .negedge_delay_ticks = 0,
  530. };
  531. // generator_a bypass the deadtime module (no delay)
  532. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
  533. // apply dead time on both edge for generator_b
  534. dead_time_config.negedge_delay_ticks = 50;
  535. dead_time_config.posedge_delay_ticks = 50;
  536. ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
  537. }
  538. .. _mcpwm-carrier-modulation:
  539. 载波调制
  540. ^^^^^^^^^^^^^^^^^^
  541. MCPWM 操作器具有载波子模块,可以根据需要(例如隔离式数字电源应用中)使用变压器传递 PWM 输出信号,实现电机驱动器的电气隔离。在电机需要在全负荷下稳定运行时,各个 PWM 输出信号都将占空比稳定保持在 100% 左右。由于变压器无法直接耦合非交替信号,需要使用载波子模块调制信号,生成交流电波形,从而实现耦合。
  542. 调用 :cpp:func:`mcpwm_operator_apply_carrier`,并提供配置结构体 :cpp:type:`mcpwm_carrier_config_t`,配置载波子模块:
  543. - :cpp:member:`mcpwm_carrier_config_t::clk_src` 设置载波的时钟源。
  544. - :cpp:member:`mcpwm_carrier_config_t::frequency_hz` 表示载波频率,单位为赫兹。内部驱动将根据时钟源和载波频率设置合适的分频器。
  545. - :cpp:member:`mcpwm_carrier_config_t::duty_cycle` 表示载波的占空比。需注意,支持的占空比选项并不连续,驱动程序将根据配置查找最接近的占空比。
  546. - :cpp:member:`mcpwm_carrier_config_t::first_pulse_duration_us` 表示第一个脉冲的脉宽,单位为微秒。该脉冲的分辨率由 :cpp:member:`mcpwm_carrier_config_t::frequency_hz` 中的配置决定。第一个脉冲的脉宽不能为零,且至少为一个载波周期。脉宽越长,电感传导越快。
  547. - :cpp:member:`mcpwm_carrier_config_t::invert_before_modulate` 和 :cpp:member:`mcpwm_carrier_config_t::invert_after_modulate` 设置是否在调制前和调制后取反载波输出。
  548. 具体而言,可调用 :cpp:func:`mcpwm_operator_apply_carrier` 并将其配置为 ``NULL``,禁用载波子模块。
  549. .. _mcpwm-faults-and-brake-actions:
  550. 故障检测和制动控制
  551. ^^^^^^^^^^^^^^^^^^^^^^^^
  552. MCPWM 操作器能够感知外部信号,接收有关电机故障、功率驱动器及其他连接设备的信息。这些故障信号封装在 MCPWM 故障对象中。
  553. 电机需配置故障模式以及检测到特定故障时的对应操作,例如拉低有刷电机的所有输出,或是锁定步进电机的电流状态等。此操作应使电机重回安全状态,降低故障导致损坏的可能性。
  554. 设置故障时操作器的制动模式
  555. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  556. MCPWM 操作器对故障的响应方式为 **制动**。可以调用 :cpp:func:`mcpwm_operator_set_brake_on_fault`,为每个故障对象配置不同的制动模式。制动的相关配置包含在结构体 :cpp:type:`mcpwm_brake_config_t` 中:
  557. - :cpp:member:`mcpwm_brake_config_t::fault` 设置操作器响应的故障类型。
  558. - :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`,手动恢复操作器。
  559. 设置发生制动事件时的生成器操作
  560. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  561. 调用 :cpp:func:`mcpwm_generator_set_actions_on_brake_event` 并辅以若干操作配置,可以针对不同的制动事件,为生成器设置不同的对应操作。操作配置定义在 :cpp:type:`mcpwm_gen_brake_event_action_t` 中:
  562. - :cpp:member:`mcpwm_gen_brake_event_action_t::direction` 指定定时器的方向,可以调用 :cpp:type:`mcpwm_timer_direction_t` 查看支持的方向。
  563. - :cpp:member:`mcpwm_gen_brake_event_action_t::brake_mode` 指定制动模式,可以调用 :cpp:type:`mcpwm_operator_brake_mode_t` 查看支持的制动模式。
  564. - :cpp:member:`mcpwm_gen_brake_event_action_t::action` 指定生成器操作,可以调用 :cpp:type:`mcpwm_generator_action_t` 查看支持的操作。
  565. 可借助辅助宏 :c:macro:`MCPWM_GEN_BRAKE_EVENT_ACTION` 构建制动事件操作条目。
  566. 需注意, :cpp:func:`mcpwm_generator_set_actions_on_brake_event` 的参数列表 **必须** 以 :c:macro:`MCPWM_GEN_BRAKE_EVENT_ACTION_END` 结束。
  567. 也可以调用 :cpp:func:`mcpwm_generator_set_action_on_brake_event` 逐一设置制动操作,无需涉及变量参数。
  568. 注册故障事件回调
  569. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  570. MCPWM 故障检测器支持在检测到实际故障或故障信号消失时发送通知。若有函数需在特定事件发生时调用,则应预先调用 :cpp:func:`mcpwm_fault_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中故障事件回调函数原型声明为 :cpp:type:`mcpwm_fault_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_fault_event_callbacks_t` 中:
  571. - :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_enter` 设置检测到故障时调用的回调函数。
  572. - :cpp:member:`mcpwm_fault_event_callbacks_t::on_fault_exit` 设置故障消失后调用的回调函数。
  573. 由于上述回调函数在 ISR 中调用,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。
  574. 函数 :cpp:func:`mcpwm_fault_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。
  575. 此函数会延迟安装 MCPWM 故障的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_fault` 移除。
  576. 寄存器制动事件回调
  577. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  578. MCPWM 操作器支持在进行制动操作前发送通知。若有函数需在特定事件发生时调用,则应预先调用 :cpp:func:`mcpwm_operator_register_event_callbacks`,将所需函数挂载至中断服务程序 (ISR) 中。驱动中制动事件回调函数原型声明为 :cpp:type:`mcpwm_brake_event_cb_t`,其所支持的事件回调类型则列在 :cpp:type:`mcpwm_operator_event_callbacks_t` 中:
  579. - :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_cbc` 设置操作器进行 **逐周期 (CBC)** 操作前调用的回调函数。
  580. - :cpp:member:`mcpwm_operator_event_callbacks_t::on_brake_ost` 设置操作器进行 **一次性 (OST)** 操作前调用的回调函数。
  581. 由于上述回调函数在 ISR 中调用,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。
  582. 函数 :cpp:func:`mcpwm_operator_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。
  583. 此函数会延迟安装 MCPWM 故障的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_operator` 移除。
  584. .. _mcpwm-generator-force-actions:
  585. 生成器强制操作
  586. ^^^^^^^^^^^^^^^^^^^^^^^
  587. 调用 :cpp:func:`mcpwm_generator_set_force_level`,使能软件强制决定运行时的生成器输出电平。相较于通过 :cpp:func:`mcpwm_generator_set_actions_on_timer_event` 配置的其他事件操作,软件强制事件优先级最高。
  588. - 设置 ``level`` 为 -1,代表禁用强制操作,生成器的输出电平重新交由事件操作控制。
  589. - 设置 ``hold_on`` 为 true,代表强制输出电平将保持不变,直到设置 ``level`` 为 -1 来移除该电平。
  590. - 设置 ``hole_on`` 为 false,代表强制输出电平仅在短时间有效,随后发生的任何事件都可以改变该电平。
  591. .. _mcpwm-synchronization:
  592. 同步模块
  593. ^^^^^^^^^^^^^^^
  594. MCPWM 定时器接收到同步信号后,定时器将强制进入一个预定义的 **相位**,该相位由计数值和计数方向共同决定。调用 :cpp:func:`mcpwm_timer_set_phase_on_sync`,设置同步相位。同步相位配置定义在 :cpp:type:`mcpwm_timer_sync_phase_config_t` 结构体中:
  595. - :cpp:member:`mcpwm_timer_sync_phase_config_t::sync_src` 设置同步信号源。创建同步源对象的相关操作,请参见 `MCPWM 同步源`_。具体来说,当此参数设置为 ``NULL`` 时,驱动器将禁用 MCPWM 定时器的同步功能。
  596. - :cpp:member:`mcpwm_timer_sync_phase_config_t::count_value` 设置接收同步信号后加载至计数器的值。
  597. - :cpp:member:`mcpwm_timer_sync_phase_config_t::direction` 设置接收同步信号后的计数方向。
  598. 同理, `MCPWM 捕获定时器和通道`_ 也支持同步。调用 :cpp:func:`mcpwm_capture_timer_set_phase_on_sync`,设置捕获定时器的同步相位。同步相位配置定义在 :cpp:type:`mcpwm_capture_timer_sync_phase_config_t` 结构体中:
  599. - :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::sync_src` 设置同步信号源。关于如何创建一个同步源对象,请参见 `MCPWM 同步源`_。具体来说,当此参数设置为 ``NULL`` 时,驱动器将禁用 MCPWM 捕获定时器的同步功能。
  600. - :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::count_value` 设置接收同步信号后加载至计数器的值。
  601. - :cpp:member:`mcpwm_capture_timer_sync_phase_config_t::direction` 设置接收同步信号后的计数方向。需注意,不同于 MCPWM 定时器,捕获定时器只支持 :cpp:enumerator:`MCPWM_TIMER_DIRECTION_UP` 这一个计数方向。
  602. 使用 GPIO 同步定时器
  603. ~~~~~~~~~~~~~~~~~~~~~~~~~
  604. .. blockdiag::
  605. :caption: GPIO Sync All MCPWM Timers
  606. :align: center
  607. blockdiag {
  608. GPIO -> Timer0, Timer1, Timer2;
  609. }
  610. .. code-block:: c
  611. static void example_setup_sync_strategy(mcpwm_timer_handle_t timers[])
  612. {
  613. mcpwm_sync_handle_t gpio_sync_source = NULL;
  614. mcpwm_gpio_sync_src_config_t gpio_sync_config = {
  615. .group_id = 0, // GPIO 故障应与以上定时器位于同一组中
  616. .gpio_num = EXAMPLE_SYNC_GPIO,
  617. .flags.pull_down = true,
  618. .flags.active_neg = false, // 默认情况下,一个上升沿脉冲可以触发一个同步事件
  619. };
  620. ESP_ERROR_CHECK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_source));
  621. mcpwm_timer_sync_phase_config_t sync_phase_config = {
  622. .count_value = 0, // 同步相位:目标计数值
  623. .direction = MCPWM_TIMER_DIRECTION_UP, // 同步相位:计数方向
  624. .sync_src = gpio_sync_source, // 同步源
  625. };
  626. for (int i = 0; i < 3; i++) {
  627. ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[i], &sync_phase_config));
  628. }
  629. }
  630. .. _mcpwm-capture:
  631. 捕获模块
  632. ^^^^^^^^^^^^^
  633. MCPWM 捕获的主要功能是记录捕获信号的脉冲边沿的有效时间。可以通过捕获得到脉宽,随后使用捕获回调函数将脉宽转换为其他物理量,如距离或速度。例如,在下图的无刷直流电机 (BLDC) 方案中,可以使用捕获子模块来确认来自霍尔传感器的转子位置。
  634. .. figure:: ../../../_static/mcpwm-bldc-control.png
  635. :align: center
  636. :alt: 带霍尔传感器的 MCPWM 无刷直流电机
  637. 带霍尔传感器的 MCPWM 无刷直流电机
  638. 通常,捕获定时器连接了数个捕获通道。有关资源分配的相关信息,请参见 `MCPWM 捕获定时器和通道`_。
  639. 注册捕获事件回调
  640. ~~~~~~~~~~~~~~~~~~~~~~~~
  641. MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须调用 :cpp:func:`mcpwm_capture_channel_register_event_callbacks`,注册一个回调函数来获得捕获的定时器计数值。回调函数原型声明在 :cpp:type:`mcpwm_capture_event_cb_t` 中,可以调用 :cpp:type:`mcpwm_capture_event_callbacks_t` 查看支持的捕获回调:
  642. - :cpp:member:`mcpwm_capture_event_callbacks_t::on_cap` 设置检测到有效边沿时捕获通道的回调函数。
  643. 回调函数会针对特定事件,提供 :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`,获取捕获定时器的分辨率,以将捕获计数转换为时间戳。
  644. 由于上述回调函数在 ISR 中调用,因此,这些函数 **不应** 涉及 block 操作。可以检查调用 API 的后缀,确保在函数中只调用了后缀为 ``ISR`` 的 FreeRTOS API。
  645. 函数 :cpp:func:`mcpwm_capture_channel_register_event_callbacks` 中的 ``user_data`` 参数用于保存用户上下文,将直接传递至各个回调函数。
  646. 此函数会延迟安装 MCPWM 捕获的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_capture_channel` 移除。
  647. 启用或禁用捕获通道
  648. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  649. 调用 :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` 启用通道时,也将启用中断服务。
  650. 启用或禁用捕获定时器
  651. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  652. 在对捕获定时器进行 IO 控制之前,需要首先调用 :cpp:func:`mcpwm_capture_timer_enable`,启用定时器。此函数将进行如下内部操作:
  653. * 将捕获定时器的状态从 **init** 切换到 **enable**。
  654. * 如果选择了一个特定时钟源(例如 APB 时钟),则获取一个对应的电源管理锁。更多信息请参见 :ref:`mcpwm-power-management`。
  655. 反之,调用 :cpp:func:`mcpwm_capture_timer_disable` 将使定时器驱动程序切换回 **init** 状态,并释放电源管理锁。
  656. 启动或停止捕获定时器
  657. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  658. 通过基本的 IO 控制,即可启动或停止捕获定时器。调用 :cpp:func:`mcpwm_capture_timer_start` 启动捕获定时器,或调用 :cpp:func:`mcpwm_capture_timer_stop` 立即停止捕获定时器。
  659. 触发软件捕获事件
  660. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  661. 某些场景下,可能存在需要软件触发“虚假”捕获事件的需求。此时,可以调用 :cpp:func:`mcpwm_capture_channel_trigger_soft_catch` 实现。需注意,此类“虚假”捕获事件仍然会触发中断,并从而调用捕获事件回调函数。
  662. .. only:: SOC_MCPWM_SUPPORT_ETM
  663. .. _mcpwm-etm-event-and-task:
  664. ETM 事件与任务
  665. ^^^^^^^^^^^^^^^^^^
  666. MCPWM 比较器可以产生事件,这些事件可以连接到 :doc:`ETM </api-reference/peripherals/etm>` 模块。:cpp:type:`mcpwm_comparator_etm_event_type_t` 中列出了 MCPWM 比较器能够产生的事件类型。用户可以通过调用 :cpp:func:`mcpwm_comparator_new_etm_event` 来获得相应事件的 ETM event 句柄。
  667. 关于如何将 MCPWM 比较器事件连接到 ETM 通道中,请参阅 :doc:`ETM </api-reference/peripherals/etm>` 文档。
  668. .. _mcpwm-power-management:
  669. .. only:: not SOC_MCPWM_SUPPORT_ETM
  670. .. _mcpwm-power-management:
  671. 电源管理
  672. ^^^^^^^^^^^^^^^^
  673. 启用电源管理(即开启 :ref:`CONFIG_PM_ENABLE`)时,系统会在进入 Light-sleep 前调整 PLL 和 APB 频率。该操作有可能会改变 MCPWM 定时器的计数步长,导致计时偏差。
  674. 不过,驱动程序可以获取 :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` 时,驱动程序释放锁。
  675. 同理,每当驱动创建一个以 :cpp:enumerator:`MCPWM_CAPTURE_CLK_SRC_APB` 作为时钟源的 MCPWM 捕获定时器实例时,都会在通过 :cpp:func:`mcpwm_capture_timer_enable` 启用定时器时获取电源管理锁,并在调用 :cpp:func:`mcpwm_capture_timer_disable` 时释放锁。
  676. .. _mcpwm-iram-safe:
  677. IRAM 安全
  678. ^^^^^^^^^^^^^
  679. 默认情况下,禁用 cache 时,写入/擦除 flash 等原因将导致 MCPWM 中断延迟,事件回调函数也将延迟执行。在实时应用程序中,应避免此类情况。
  680. 因此,可以启用 Kconfig 选项 :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE`,该选项:
  681. * 支持在禁用 cache 时启用所需中断
  682. * 支持将 ISR 使用的所有函数存放在 IRAM 中 [2]_
  683. * 支持将驱动程序存放在 DRAM 中(以防其意外映射到 PSRAM 中)
  684. 启用该选项可以保证 cache 禁用时的中断运行,但会相应增加 IRAM 占用。
  685. 另一个 Kconfig 选项 :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` 也支持将常用的 IO 控制函数存放在 IRAM 中,以保证在禁用 cache 时可以正常使用函数。IO 控制函数如下所示:
  686. - :cpp:func:`mcpwm_comparator_set_compare_value`
  687. - :cpp:func:`mcpwm_timer_set_period`
  688. .. _mcpwm-thread-safety:
  689. 线程安全
  690. ^^^^^^^^^^^^^
  691. 驱动程序会确保工厂函数(如 :cpp:func:`mcpwm_new_timer`)的线程安全,使用时,可以直接从不同的 RTOS 任务中调用此类函数,无需额外锁保护。
  692. 驱动程序设置了临界区,以防函数同时在任务和 ISR 中调用。因此,以下函数支持在 ISR 上下文运行:
  693. - :cpp:func:`mcpwm_comparator_set_compare_value`
  694. - :cpp:func:`mcpwm_timer_set_period`
  695. :ref:`mcpwm-resource-allocation-and-initialization` 中尚未提及的函数并非线程安全。在没有设置互斥锁保护的任务中,应避免调用这些函数。
  696. .. _mcpwm-kconfig-options:
  697. Kconfig 选项
  698. ^^^^^^^^^^^^^^^
  699. - :ref:`CONFIG_MCPWM_ISR_IRAM_SAFE` 控制默认 ISR 处理程序能否在禁用 cache 的情况下工作。更多信息请参见 :ref:`mcpwm-iram-safe`。
  700. - :ref:`CONFIG_MCPWM_CTRL_FUNC_IN_IRAM` 控制 MCPWM 控制函数的存放位置(IRAM 或 flash)。更多信息请参见 :ref:`mcpwm-iram-safe`。
  701. - :ref:`CONFIG_MCPWM_ENABLE_DEBUG_LOG` 用于启用调试日志输出。启用此选项将增加固件的二进制文件大小。
  702. 应用示例
  703. --------------------
  704. * 通过 PID 算法控制有刷直流电机速度::example:`peripherals/mcpwm/mcpwm_bdc_speed_control`
  705. * 控制带霍尔传感器反馈的无刷直流电机::example:`peripherals/mcpwm/mcpwm_bldc_hall_control`
  706. * 使用超声波传感器 (HC-SR04) 测量距离::example:`peripherals/mcpwm/mcpwm_capture_hc_sr04`
  707. * 控制伺服电机角度::example:`peripherals/mcpwm/mcpwm_servo_control`
  708. * 定时器之间的 MCPWM 同步::example:`peripherals/mcpwm/mcpwm_sync`
  709. API Reference
  710. -------------
  711. .. include-build-file:: inc/mcpwm_timer.inc
  712. .. include-build-file:: inc/mcpwm_oper.inc
  713. .. include-build-file:: inc/mcpwm_cmpr.inc
  714. .. include-build-file:: inc/mcpwm_gen.inc
  715. .. include-build-file:: inc/mcpwm_fault.inc
  716. .. include-build-file:: inc/mcpwm_sync.inc
  717. .. include-build-file:: inc/mcpwm_cap.inc
  718. .. include-build-file:: inc/mcpwm_etm.inc
  719. .. include-build-file:: inc/components/esp_driver_mcpwm/include/driver/mcpwm_types.inc
  720. .. include-build-file:: inc/components/hal/include/hal/mcpwm_types.inc
  721. .. [1]
  722. 不同的 ESP 芯片上的 MCPWM 资源数量可能存在差异(如组、定时器、比较器、操作器、生成器、触发器等)。详情请参见 [`TRM <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__]。当分配了超出资源数量的 MCPWM 资源时,在检测到没有可用硬件资源后,驱动程序将返回错误。请在进行 :ref:`mcpwm-resource-allocation-and-initialization` 时务必检查返回值。
  723. .. [2]
  724. 回调函数及其调用的子函数需手动存放进 IRAM 中。