STM32 HRTIM 学习心得(2):控制输出 PWM/SPWM/带死区的互补SPWM

1. 输出固定的 PWM

时钟树等基础功能配置,这里不做说明,请自行研究。

找到 HRTIM 定时器,配置使能 CH1A 输出:

设置 CH1A 输出频率 20KHz 占空比百分之 50% 的 PWM 方波,我们采用 Compare 1 的功能,来翻转 CH1A 引脚从而实现 PWM 的控制输出,其原理如下图所示:

配置 TimerA 定时器,如下:

  1. 选择 Advanced (using HAL_Waveform methods) 。
  2. 我的芯片使用的是 STM32G474 最大主频是 170MHz,这里选择 Prescalor 使用 170MHz 的基准时钟。
  3. 设置 PWM 输出的频率为 20KHz,即 P e r i o d = 170 M H z 20 K H z = 8500 Period = \frac{170MHz}{20KHz} = 8500 Period=20KHz170MHz=8500
  4. 设置 PWM 的占空比为百分之五十,则为 8500 ÷ 2 = 4250 8500 \div 2 = 4250 8500÷2=4250

我们需要在 CubeMx 里面设置当每次 Counter 的值与 Compare 1 相同时就触发 TA1 信号翻转:

接着在配置 TA1 输出端口:

  1. 配置输出信号来自 TA1 (Timer A);
  2. 输出的有效电平为高电平(Ouput is ative HIGH)
  3. 当 Compare1 事件触发时,输出为高电平;
  4. 当 Period 事件触发时(定时器计数器达到 Period 的值),触发输出为低电平;

设置完成后生成代码即可。

在程序的应用层,需要通过软件手动开启 PWM 的输出:

c++ 复制代码
#include "stm32g474xx.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_hrtim.h"

#include "FocService.hpp"

extern HRTIM_HandleTypeDef hhrtim1;

bool FocService::init()
{
    HAL_HRTIM_SimpleOCStart(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A, HRTIM_OUTPUT_TA1);

    return true;
}

void FocService::yield()
{
}

我通过 HAL_HRTIM_SimpleOCStart 开启了 PWM 的输出。

2. SPWM

2.1 SPWM 介绍

SPWM 的原理是基于载波和正选波的交点,当载波大于正选波时输出高电平,当载波小于正选波的时候输出低电平。

更详细的介绍可以参考 SPWM基本原理详解(图文并茂+公式推导+C程序实现)

我们定义载波(上图的三角形)为 V s V_s Vs,其电压其幅值为 V s m V_{sm} Vsm,频率为 f c f_c fc 的三角波;

再定义正弦波的电压表达式为:
V a m = V m ∗ s i n ( ω t ) V_{am} = V_m*sin(\omega t) Vam=Vm∗sin(ωt)

定义载波(三角波)和调制波(正弦波)的幅值之比为: m m = V m V s m m_m = \frac{V_m}{V_{sm}} mm=VsmVm,称为调制深度。

定义载波和生成出来的 SPWM 的频率之比为载波比,即: m f = f c f m_f = \frac{f_c}{f} mf=ffc, f f f 为 PWM 的频率;

2.2 Matlab 仿真 SPWM

模型设计如下:

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2d5ade8728c94d1c9e756c1b0ef455d3.png#pic_center

载波发生器,采用频率为 5KHz 的载波:

使用频率为 50Hz 的调制波:

设置模型的步长为 0.0001s,查看结果到如下的 SPWM 波形:

2.3 HRTIM 输出 SPWM

通过 Matlab 直观得观察到 SPWM 的输出波形,那么如何在 STM32 的 HRTIM 中设计这个波形呢?

这里采用面积等效法来实现,设计思路如下:

详细可以参考 【嵌入式】STM32输出SPWM实现逆变

  1. SPWM逆变的精髓就是【冲量等效原理】------将一周期正弦波等分为 N 段,每段的长度为 T,可以算出任意一段的积分面积 S (即正弦波在 T 时间段内与横轴围成的面积),如果在每一段 T 时间段内,SPWM 波与横轴围成的面积都等于 T 内正弦波的定积分 S,那么在后级对 SPWM 进行滤波后即可得到正弦波。

  2. 确定载波频率 f b f_b fb:载波即下图中红线标出的波形,占空比的调整都在每个载波周期内进行。对于单片机,我们只需要控制在某个载波周期内,高低电平所占的时间即可。一般来讲,载波频率越高,滤出的正弦波越细腻,能调出的正弦波频率上限也越高。

  3. 确定正弦波频率 f s f_s fs

  4. 得到正弦波一周波分段 N:
    N = f b f s N=\frac{f_b}{f_s} N=fsfb ,由此可见,正弦波频率越低,N 越大,基波频率越低,N 越小。

  5. 分段计算正弦波积分 S,得出 PWM 占空比序列

    这里的分段计算,就是在整个正弦波一周期内,依次计算。计算出每段S后,另 PWM 与横轴围成的面积等于 S,即可得出该段的 PWM 占空比。一周期计算完成后,即得出了 PWM 的占空比序列。

掌握以上原理后,需要先通过软件计算生成 spwm 序列,根据以上原理,编写 matlab 程序如下:

matlab 复制代码
%-----硬件设置-------------------------------------
timerCLK = 170000000; %timer时钟,170MHz/1分频
Period   = 8500;      %载波频率设计为 20KHz
baseRate = timerCLK / (Period + 1); %载波频率 20KHz
%-----正弦波设置------------------------------------
F          = 50;%频率
T          = 1/F;%周期
ampScale   = 0.85;%调幅
N          = round(baseRate / F);%一周波分多少段
stepTime   = 1/F/N; %积分步进值(每一段的长度)
%-----计算------------------------------------------
CCR  = (1:1:N)';

for i=1:1:N
    area   = double(quad(@(x)sin(2*pi*F*x),(i-1)*stepTime,i*stepTime));
    CCR(i) = round((ampScale*area*Period / stepTime + Period) / 2);
end

基于中断实现

CubeMX 配置输出:

  1. Time Base 设置
    设置 PWM 的输出频率为 20KHz 也就是载波的频率,采用 up-counting 方式:
  2. 配置 Timing Unit
    • Preload Enable:配置为 Enable,当我们更新 Compare1 的值不会直接写入 Compare1 的寄存器,而且写入 Compare1 的 Preload 寄存器,在 Timer 中有多个寄存器是存在 Preload 寄存器,下图中有两个框的寄存器都是带 Preload 功能的:
    • Reset Update:在 Timer reset 或者触发 roll-over 的时候更新寄存器的值,Timer Reset 的来自 crossbars 上面的 Reset 事件可以触发,roll-over 当计数器的值重新变为 0 的时候会触发这个事件;因此,可以实现在计数器变为零的时候,将Compare1 的 Preload 更新到 Compare1。
    • Interrupt Requests Sources Selection:设置 Timer update interrupt enable,在定时器值更新过后触发中断。我们就可以将新的 Compare1 的值填到 Preload 里面;
  3. Compare1 的配置
  4. 输出端口配置
  5. 开启 Timer A 的中断

第 3、4点的配置正常的 PWM 输出一致。

程序实现:

c 复制代码
#include "spwm.h"

#include "stm32g474xx.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_hrtim.h"

const uint16_t g_tFb20KHz_Fs50Hz[400] = {
    4278, 4335, 4392, 4449, 4505, 4562, 4618, 4675, 4731, 4787,
    4843, 4899, 4955, 5010, 5066, 5121, 5176, 5231, 5285, 5339, 
    5393, 5447,5500, 5553, 5606, 5659, 5711,5762, 5814, 5865, 
    5915, 5965, 6015, 6064, 6113, 6162, 6210, 6257, 6304, 6350,
    6396, 6442, 6486, 6531, 6574, 6618, 6660, 6702, 6744, 6784,
    6824, 6864, 6903, 6941, 6978, 7015, 7051, 7087, 7122, 7156,
    7189, 7222, 7254, 7285, 7315, 7345, 7374, 7402, 7429, 7456,
    7482, 7506, 7531, 7554, 7577, 7598, 7619, 7639, 7658, 7677,
    7694, 7711, 7727, 7742, 7756, 7769, 7782, 7793, 7804, 7813,
    7822, 7830, 7837, 7844, 7849, 7853, 7857, 7860, 7861, 7862,
    7862, 7861, 7860, 7857, 7853, 7849, 7844, 7837, 7830, 7822,
    7813, 7804, 7793, 7782, 7769, 7756, 7742, 7727, 7711, 7694,
    7677, 7658, 7639, 7619, 7598, 7577, 7554, 7531, 7506, 7482,
    7456, 7429, 7402, 7374, 7345, 7315, 7285, 7254, 7222, 7189,
    7156, 7122, 7087, 7051, 7015, 6978, 6941, 6903, 6864, 6824,
    6784, 6744, 6702, 6660, 6618, 6574, 6531, 6486, 6442, 6396,
    6350, 6304, 6257, 6210, 6162, 6113, 6064, 6015, 5965, 5915,
    5865, 5814, 5762, 5711, 5659, 5606, 5553, 5500, 5447, 5393,
    5339, 5285, 5231, 5176, 5121, 5066, 5010, 4955, 4899, 4843,
    4787, 4731, 4675, 4618, 4562, 4505, 4449, 4392, 4335, 4278,
    4222, 4165, 4108, 4051, 3995, 3938, 3882, 3825, 3769, 3713,
    3657,3601,3545,3490,3434,3379,3324,3269,3215,3161,
    3107, 3053, 3000, 2947, 2894, 2841, 2789, 2738, 2686, 2635, 
    2585, 2535, 2485, 2436, 2387, 2338, 2290, 2243, 2196, 2150, 
    2104, 2058, 2014, 1969, 1926, 1882, 1840, 1798, 1756, 1716, 
    1676, 1636, 1597, 1559, 1522, 1485, 1449, 1413, 1378, 1344, 
    1311, 1278, 1246, 1215, 1185, 1155, 1126, 1098, 1071, 1044, 
    1018, 994, 969, 946, 923, 902, 881, 861, 842, 823,
    806, 789, 773, 758, 744, 731, 718, 707, 696, 687, 
    678, 670, 663, 656, 651, 647, 643, 640, 639, 638, 
    638, 639, 640, 643, 647, 651, 656, 663, 670, 678, 
    687, 696, 707, 718, 731, 744, 758, 773, 789, 806, 
    823, 842, 861, 881, 902, 923, 946, 969, 994, 1018, 
    1044, 1071, 1098, 1126, 1155, 1185, 1215, 1246, 1278, 1311, 
    1344, 1378, 1413, 1449, 1485, 1522, 1559, 1597, 1636, 1676, 
    1716, 1756, 1798, 1840, 1882, 1926, 1969, 2014, 2058, 2104, 
    2150, 2196, 2243, 2290, 2338, 2387, 2436, 2485, 2535, 2585, 
    2635, 2686, 2738, 2789, 2841, 2894, 2947, 3000, 3053, 3107, 
    3161, 3215, 3269, 3324, 3379, 3434, 3490, 3545, 3601, 3657, 
    3713, 3769, 3825, 3882, 3938, 3995, 4051, 4108, 4165, 4222
};


extern HRTIM_HandleTypeDef hhrtim1;
static uint16_t            s_index = 0;

// 更新 Compare1 的值
static void spwm_compare1_update(HRTIM_HandleTypeDef *hhrtim, uint16_t TimerIdx)
{
    __HAL_HRTIM_SETCOMPARE(hhrtim, TimerIdx, HRTIM_COMPAREUNIT_1, g_tFb20KHz_Fs50Hz[s_index]);
    s_index = (s_index + 1) % (sizeof(g_tFb20KHz_Fs50Hz)/sizeof(uint16_t));
}

bool spwm_init(void)
{
	// 让 SPWM 初始的输出为 g_tFb20KHz_Fs50Hz 中的第一个
    spwm_compare1_update(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A);
    HAL_HRTIM_WaveformCountStart_IT(&hhrtim1, HRTIM_TIMERID_TIMER_A);
    HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1);
    return true;
}

void spwm_yield(void)
{
}

// 我们在定时器更新事件回调里面更新 Compare1 的值
void HAL_HRTIM_RegistersUpdateCallback(HRTIM_HandleTypeDef *hhrtim, uint32_t TimerIdx)
{
    if (TimerIdx == HRTIM_TIMERINDEX_TIMER_A) {
        spwm_compare1_update(hhrtim, HRTIM_TIMERINDEX_TIMER_A);
    }
}

最后的输出波形的展示:

基于 DMA 实现

上面基于中断的实现,在我们想实现更高频率的载波时,可能会存在一定的局限性,需要消耗 CPU 时间、以及触发中断等一系列操作。

那么一个优化的方向就是可以考虑使用 DMA 来实现:

  1. 开启 DMA,设置传输方向为内存到外设,设置 Half word 和 Circular 循环传输:
  2. 关闭 Timer A 的中断,不再需要:
  3. 配置 Timer A 的 Timing Unit
  • 开启一个 DMA 传输的触发源,配置为 Timer Compare1,一旦 Compare1 信号触发就让 DMA 帮我们将新的 Compare1 的值传入到 Preload 寄存器里;
  • DMA Src Address:指定为内存地址,也就是我们的 (uint32_t)(&(g_tFb20KHz_Fs50Hz[0]))
  • DMA Dst Address:指定为定时器的 Compare1,开启了 Preload Enable 后,实际上是传入到对应的 Preload 寄存器,即 (uint32_t)(&(hhrtim1.Instance->sTimerxRegs[HRTIM_TIMERINDEX_TIMER_A].CMP1xR))
  • DMA Size:注意把右边的 No check 打开,然后就可以通过 sizeof 动态指定要传输的大小,即 (uint32_t)(sizeof(g_tFb20KHz_Fs50Hz)/sizeof(uint16_t))

然后对我们的中断程序稍加修改:

c 复制代码
#include "spwm.h"

#include "stm32g474xx.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_hrtim.h"

const uint16_t g_tFb20KHz_Fs50Hz[400] = {
    4278, 4335, 4392, 4449, 4505, 4562, 4618, 4675, 4731, 4787,
    4843, 4899, 4955, 5010, 5066, 5121, 5176, 5231, 5285, 5339, 
    5393, 5447,5500, 5553, 5606, 5659, 5711,5762, 5814, 5865, 
    5915, 5965, 6015, 6064, 6113, 6162, 6210, 6257, 6304, 6350,
    6396, 6442, 6486, 6531, 6574, 6618, 6660, 6702, 6744, 6784,
    6824, 6864, 6903, 6941, 6978, 7015, 7051, 7087, 7122, 7156,
    7189, 7222, 7254, 7285, 7315, 7345, 7374, 7402, 7429, 7456,
    7482, 7506, 7531, 7554, 7577, 7598, 7619, 7639, 7658, 7677,
    7694, 7711, 7727, 7742, 7756, 7769, 7782, 7793, 7804, 7813,
    7822, 7830, 7837, 7844, 7849, 7853, 7857, 7860, 7861, 7862,
    7862, 7861, 7860, 7857, 7853, 7849, 7844, 7837, 7830, 7822,
    7813, 7804, 7793, 7782, 7769, 7756, 7742, 7727, 7711, 7694,
    7677, 7658, 7639, 7619, 7598, 7577, 7554, 7531, 7506, 7482,
    7456, 7429, 7402, 7374, 7345, 7315, 7285, 7254, 7222, 7189,
    7156, 7122, 7087, 7051, 7015, 6978, 6941, 6903, 6864, 6824,
    6784, 6744, 6702, 6660, 6618, 6574, 6531, 6486, 6442, 6396,
    6350, 6304, 6257, 6210, 6162, 6113, 6064, 6015, 5965, 5915,
    5865, 5814, 5762, 5711, 5659, 5606, 5553, 5500, 5447, 5393,
    5339, 5285, 5231, 5176, 5121, 5066, 5010, 4955, 4899, 4843,
    4787, 4731, 4675, 4618, 4562, 4505, 4449, 4392, 4335, 4278,
    4222, 4165, 4108, 4051, 3995, 3938, 3882, 3825, 3769, 3713,
    3657,3601,3545,3490,3434,3379,3324,3269,3215,3161,
    3107, 3053, 3000, 2947, 2894, 2841, 2789, 2738, 2686, 2635, 
    2585, 2535, 2485, 2436, 2387, 2338, 2290, 2243, 2196, 2150, 
    2104, 2058, 2014, 1969, 1926, 1882, 1840, 1798, 1756, 1716, 
    1676, 1636, 1597, 1559, 1522, 1485, 1449, 1413, 1378, 1344, 
    1311, 1278, 1246, 1215, 1185, 1155, 1126, 1098, 1071, 1044, 
    1018, 994, 969, 946, 923, 902, 881, 861, 842, 823,
    806, 789, 773, 758, 744, 731, 718, 707, 696, 687, 
    678, 670, 663, 656, 651, 647, 643, 640, 639, 638, 
    638, 639, 640, 643, 647, 651, 656, 663, 670, 678, 
    687, 696, 707, 718, 731, 744, 758, 773, 789, 806, 
    823, 842, 861, 881, 902, 923, 946, 969, 994, 1018, 
    1044, 1071, 1098, 1126, 1155, 1185, 1215, 1246, 1278, 1311, 
    1344, 1378, 1413, 1449, 1485, 1522, 1559, 1597, 1636, 1676, 
    1716, 1756, 1798, 1840, 1882, 1926, 1969, 2014, 2058, 2104, 
    2150, 2196, 2243, 2290, 2338, 2387, 2436, 2485, 2535, 2585, 
    2635, 2686, 2738, 2789, 2841, 2894, 2947, 3000, 3053, 3107, 
    3161, 3215, 3269, 3324, 3379, 3434, 3490, 3545, 3601, 3657, 
    3713, 3769, 3825, 3882, 3938, 3995, 4051, 4108, 4165, 4222
};


extern HRTIM_HandleTypeDef hhrtim1;
static uint16_t            s_index = 0;

static void spwm_compare1_update(HRTIM_HandleTypeDef *hhrtim, uint16_t TimerIdx)
{
    __HAL_HRTIM_SETCOMPARE(hhrtim, TimerIdx, HRTIM_COMPAREUNIT_1, g_tFb20KHz_Fs50Hz[s_index]);
    s_index = (s_index + 1) % (sizeof(g_tFb20KHz_Fs50Hz)/sizeof(uint16_t));
}

bool spwm_init(void)
{
    spwm_compare1_update(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A);
    HAL_HRTIM_WaveformCountStart_DMA(&hhrtim1, HRTIM_TIMERID_TIMER_A);
    HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1);
    return true;
}

void spwm_yield(void)
{
}

烧录后,同样实现了我们想要的效果:

3. 对 SPWM 增加互补输出

SPWM 一个常见的应用就是控制电机、逆变器的 H 敲。

例如:G1 和 G4 导通时,输出电压为 +Udc,G2 和 G3 导通时, 输出电压为 -Udc

配合上 SPWM 就可以实现,如下图的波形:

再加上电容电感进行滤波,我们就可以还原出被调制的正弦波,这也就是我们前面通过 SPWM 调制正弦函数的意义!!!

因此,我们需要在 G1/G4 闭合时断开 G2/G3,反之依然。要实现这个功能,可以借助互补 HRTIM 的一些机制来帮助我们实现这个互补输出。

下面在 SPWM 的基础上为其添加一个带互补输出的通道 TA2:

  1. 将 Timer A 改为双通道输出
  2. 设置 TA2 的输出,其刚好与 TA1 相反:

    最后修改应用层程序:
c++ 复制代码
#include "spwm.h"

#include "stm32g474xx.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_hrtim.h"

const uint16_t g_tFb20KHz_Fs50Hz[400] = {
    4278, 4335, 4392, 4449, 4505, 4562, 4618, 4675, 4731, 4787,
    4843, 4899, 4955, 5010, 5066, 5121, 5176, 5231, 5285, 5339, 
    5393, 5447,5500, 5553, 5606, 5659, 5711,5762, 5814, 5865, 
    5915, 5965, 6015, 6064, 6113, 6162, 6210, 6257, 6304, 6350,
    6396, 6442, 6486, 6531, 6574, 6618, 6660, 6702, 6744, 6784,
    6824, 6864, 6903, 6941, 6978, 7015, 7051, 7087, 7122, 7156,
    7189, 7222, 7254, 7285, 7315, 7345, 7374, 7402, 7429, 7456,
    7482, 7506, 7531, 7554, 7577, 7598, 7619, 7639, 7658, 7677,
    7694, 7711, 7727, 7742, 7756, 7769, 7782, 7793, 7804, 7813,
    7822, 7830, 7837, 7844, 7849, 7853, 7857, 7860, 7861, 7862,
    7862, 7861, 7860, 7857, 7853, 7849, 7844, 7837, 7830, 7822,
    7813, 7804, 7793, 7782, 7769, 7756, 7742, 7727, 7711, 7694,
    7677, 7658, 7639, 7619, 7598, 7577, 7554, 7531, 7506, 7482,
    7456, 7429, 7402, 7374, 7345, 7315, 7285, 7254, 7222, 7189,
    7156, 7122, 7087, 7051, 7015, 6978, 6941, 6903, 6864, 6824,
    6784, 6744, 6702, 6660, 6618, 6574, 6531, 6486, 6442, 6396,
    6350, 6304, 6257, 6210, 6162, 6113, 6064, 6015, 5965, 5915,
    5865, 5814, 5762, 5711, 5659, 5606, 5553, 5500, 5447, 5393,
    5339, 5285, 5231, 5176, 5121, 5066, 5010, 4955, 4899, 4843,
    4787, 4731, 4675, 4618, 4562, 4505, 4449, 4392, 4335, 4278,
    4222, 4165, 4108, 4051, 3995, 3938, 3882, 3825, 3769, 3713,
    3657,3601,3545,3490,3434,3379,3324,3269,3215,3161,
    3107, 3053, 3000, 2947, 2894, 2841, 2789, 2738, 2686, 2635, 
    2585, 2535, 2485, 2436, 2387, 2338, 2290, 2243, 2196, 2150, 
    2104, 2058, 2014, 1969, 1926, 1882, 1840, 1798, 1756, 1716, 
    1676, 1636, 1597, 1559, 1522, 1485, 1449, 1413, 1378, 1344, 
    1311, 1278, 1246, 1215, 1185, 1155, 1126, 1098, 1071, 1044, 
    1018, 994, 969, 946, 923, 902, 881, 861, 842, 823,
    806, 789, 773, 758, 744, 731, 718, 707, 696, 687, 
    678, 670, 663, 656, 651, 647, 643, 640, 639, 638, 
    638, 639, 640, 643, 647, 651, 656, 663, 670, 678, 
    687, 696, 707, 718, 731, 744, 758, 773, 789, 806, 
    823, 842, 861, 881, 902, 923, 946, 969, 994, 1018, 
    1044, 1071, 1098, 1126, 1155, 1185, 1215, 1246, 1278, 1311, 
    1344, 1378, 1413, 1449, 1485, 1522, 1559, 1597, 1636, 1676, 
    1716, 1756, 1798, 1840, 1882, 1926, 1969, 2014, 2058, 2104, 
    2150, 2196, 2243, 2290, 2338, 2387, 2436, 2485, 2535, 2585, 
    2635, 2686, 2738, 2789, 2841, 2894, 2947, 3000, 3053, 3107, 
    3161, 3215, 3269, 3324, 3379, 3434, 3490, 3545, 3601, 3657, 
    3713, 3769, 3825, 3882, 3938, 3995, 4051, 4108, 4165, 4222
};


extern HRTIM_HandleTypeDef hhrtim1;
static uint16_t            s_index = 0;

static void spwm_compare1_update(HRTIM_HandleTypeDef *hhrtim, uint16_t TimerIdx)
{
    __HAL_HRTIM_SETCOMPARE(hhrtim, TimerIdx, HRTIM_COMPAREUNIT_1, g_tFb20KHz_Fs50Hz[s_index]);
    s_index = (s_index + 1) % (sizeof(g_tFb20KHz_Fs50Hz)/sizeof(uint16_t));
}

bool spwm_init(void)
{
    spwm_compare1_update(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A);
    HAL_HRTIM_WaveformCountStart_DMA(&hhrtim1, HRTIM_TIMERID_TIMER_A);
    HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1);
    HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA2);
    return true;
}

void spwm_yield(void)
{
}

在原来的基础上打开 HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA2); 的输出。

输出波形如下:

4. 为互补 SPWM 增加死区

还是回到前面的 H 桥,MOS 管在导通时是需要时间的,即可能存在 G1 还没有完全关断的情况下 G2 被正处于打开中,这时就可能造成 G1 和 G2 同时被打开的意外情况,这时候会导致电源直接短路,从而烧穿我们的两个 MOS 管,为了避免这种情况,最后是在 G1 断开和 G2 打开直接插入一小段间隙,确保 G1 完全断开后再打开 G2,反之同理,这个小段间隙就可以称为死区。

HRTIM 提供了一个很简便的死区插入方式:

The Dead time insertion is enabled by setting DTEN bit in HRTIM_OUTxR register. The complementary signals are built based on the reference waveform defined for output 1, using HRTIM_SETx1R and HRTIM_RSTx1R registers: HRTIM_SETx2R and HRTIM_RSTx2R registers are not significant when DTEN bit is set.

我们只需要设置 HRTIM_OUTxR 寄存器里面的 DTEN 使能,互补输出信号就会参考 CH1A 的输出,这是只使用 HRTIM_SETx1R 和 HRTIM_RSTx1R 两个寄存器来控制两个通道的输出。CH2A 的 HRTIM_SETx2R 和 HRTIM_RSTx2R 寄存器直接被忽略掉。啥意思呢?就是说,HRTIM 会在 CHA1 要输出的高电平时,自动将 CHA2 拉低,同时在 CHA1 的电平切换的前后自动插入两个间隙时间,这两个间隙时间就作为死区。

因此,我们借助这个在 CHA1 前后插入一段间隙的特性(甚至插入一个负间隙),我们可以制造出如下这些波形:

死区的时长配置公式,如下:
t D T x = + / − D T x [ 8 : 0 ] × t D T G t_{DTx} = +/- DTx[8:0] \times t_{DTG} tDTx=+/−DTx[8:0]×tDTG

其中,
t D T G = ( 2 ( D T P R S C [ 2 : 0 ] ) ) × ( t H R T I M / 8 ) . t_{DTG} = (2^{(DTPRSC[2:0])}) \times (t_{HRTIM} / 8). tDTG=(2(DTPRSC[2:0]))×(tHRTIM/8).

啥意思呢?下面这张图展示了死区的时长配置:

  • DTPRSC[2:0]:控制死区的预分频系数,也就是最小的时间刻度;
  • DTx[8:0]:控制总的刻度数;

例如,我的假设目前通过 DTPRSC[2:0] 配合 f H R T I M f_{HRTIM} fHRTIM,组合后设置的最小时间刻度是 1ns,那么我设置 DTx[8:0] = 2,那么也就是说我设置我的死区为 2ns。

我目前的 PWM 频率是 20KHz,也就是 1 s 20 × 10 3 = 50 u s \frac{1s}{20 \times 10^3} = 50us 20×1031s=50us。如果我设置上下死区都为 1us,应该也能很好得观察到波形。我们的基准 f H R T I M f_{HRTIM} fHRTIM 是 170MHz,计算一下 1 u s 5.89 n s = 169.779.... ≈ 170 \frac{1us}{5.89ns} = 169.779.... \approx 170 5.89ns1us=169.779....≈170,因此我们设置 DTx[8:0] 为 170。

  1. 开启插入死区

  2. 配置死区

    我这里都指定了 Positive deadtime,即插入一个正值的死区,此外设置了死区为 Lock 确保在中途中无法被写入。

应用程序不需要改动,生成代码即可,运行后效果如下,在两个波之间刚好插入了 1us 的死区:

5. 小结

本篇完成了 HRTIM 常用功能的探索,这些功能基本能够完成我们很多应用了。

相关推荐
不做无法实现的梦~11 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶
熊猫_豆豆15 小时前
同步整流 Buck 降压变换器
单片机·嵌入式硬件·matlab
chenchen0000000019 小时前
49元能否买到四核性能?HZ-RK3506G2_MiniEVM开发板评测:MCU+三核CPU带来的超高性价比
单片机·嵌入式硬件
孤芳剑影20 小时前
反馈环路设计总结
嵌入式硬件·学习
dump linux21 小时前
设备树子系统与驱动开发入门
linux·驱动开发·嵌入式硬件
专注VB编程开发20年21 小时前
简易虚拟 PLC 服务器-流水线自动化,上位机程序维护升级,西门子PLC仿真
服务器·单片机·自动化·上位机·plc·流水线·工控
LeoZY_21 小时前
CH347/339W开源项目:集SPI、I2C、JTAG、SWD、UART、GPIO多功能为一体(3)
stm32·单片机·嵌入式硬件·mcu·开源
chenchen000000001 天前
国产显示芯势力新篇章:内置DDR+四核A35!MY-SSD2351-MINI开发板深度评测
驱动开发·嵌入式硬件
BackCatK Chen1 天前
第13篇:TMC2240 StallGuard4失速检测|寄存器配置+状态读取(保姆级)
单片机·嵌入式硬件·tmc2240·stm32实战·stallguard4·失速检测·电机故障识别
Hello_Embed1 天前
libmodbus STM32 板载串口实验(双串口主从通信)
笔记·stm32·单片机·学习·modbus